posted on July 4, 2007

讨论一下类似BlogEngine为何要一次性加载所有Post到内存

Tagged Under : Asp.net, BlogEngine.NET, LazyLoad

试验了一下给BlogEngine生成10000个post 程序第一次运行时等待的时间让我想自杀(白屏了近2分钟)
看了一下代码,发现BlogEngine在第一次运行时候加载所有Post(从数据库)到List内,类似(Early initialization)
当新添加post时,给数据库(xml/database)内加入该post同时给List内追加该post
删除一个post时候从数据库(xml/database)内删除并从List内remove该post

  1
  2private string _Content;
  3/// <summary>
  4/// Gets or sets the Content or the post.
  5/// </summary>

  6public string Content
  7{
  8  get
  9  {
 10      if ( _Content == null )
 11      {
 12        _Content = LoadPostContent( this.Id );
 13      }

 14      return _Content;
 15  }

 16  set
 17  {
 18      if ( _Content != value )
 19      MarkDirty( "Content" );
 20      _Content = value;
 21  }

 22}

 23private string LoadPostContent(Guid id)
 24{    
 25    string content = null;
 26    
 27    string key = string.Format("Be:Content:{0}",id);
 28    
 29    // if there is no content cached
 30    object obj = HttpContext.Current.Cache.Get(key);
 31    if(obj == null)
 32    {
 33        // load the post's content from provider here
 34        content =  BlogService.LoadPostContent( id );
 35        
 36        HttpContext.Current.Cache.Insert(key, content, null, DateTime.Now.AddMinutes(2), TimeSpan.Zero);
 37            
 38        // if use xml store the data 
 39        // 更丑陋点的 new CacheDependency(_Folder + "posts\\" + id.ToString() + ".xml") in the Cache.Insert Method 
 40    }

 41
 42}

 43
 44private static object _SyncRoot = new object();
 45private static List<Post> _Posts;
 46/// <summary>
 47/// A sorted collection of all posts in the blog.
 48/// Sorted by date.
 49/// </summary>

 50public static List<Post> Posts
 51{
 52    get
 53    {
 54        lock (_SyncRoot)
 55        {
 56          if (_Posts == null)
 57          {
 58            //in provider the 'FillPosts' method' dose not return the 'real'  content' per post; 
 59
 60            _Posts = BlogService.FillPosts( );
 61          }

 62          return _Posts;
 63        }

 64    }

 65}

 66
 67in XmlBlogProvider
 68
 69/// <summary>
 70/// Retrieves a post based on the specified Id.
 71/// </summary>

 72public override Post SelectPost(Guid id)
 73{
 74    string fileName = _Folder + "posts\\" + id.ToString() + ".xml";
 75    Post post = new Post();
 76    XmlDocument doc = new XmlDocument();
 77    doc.Load(fileName);
 78
 79    post.Title = doc.SelectSingleNode("post/title").InnerText;
 80    post.Description = doc.SelectSingleNode("post/description").InnerText;
 81
 82    post.Content = null;  // dose not return the 'real'  content'
 83
 84    post.DateCreated = DateTime.Parse(doc.SelectSingleNode("post/pubDate").InnerText);
 85    post.DateModified = DateTime.Parse(doc.SelectSingleNode("post/lastModified").InnerText);
 86    
 87    // setting other filed
 88
 89    return post;
 90}

 91Post class in Business object layer
 92
 93private string _Content;
 94/// <summary>
 95/// Gets or sets the Content or the post.
 96/// </summary>

 97public string Content
 98{
 99  get
100  {
101      if ( _Content == null )
102      {
103      _Content = LoadPostContent( this.Id );
104      }

105      return _Content;
106  }

107  set
108  {
109      if ( _Content != value )
110      MarkDirty( "Content" );
111      _Content = value;
112  }

113}

114private string LoadPostContent(Guid id)
115{    
116    string key = string.Format("Be:Content:{0}",id);
117    string content = null;
118    // if there is no content cached by id
119    object obj = HttpContext.Current.Cache.Get(key);
120    if(obj == null)
121    {
122        // load the post's content from provider here
123        content =  BlogService.LoadPostContent( id );
124        
125        HttpContext.Current.Cache.Insert(key, content, null, DateTime.Now.AddMinutes(2), TimeSpan.Zero);
126            
127        // if use xml store the data 
128        // we can use a  CacheDependency like new CacheDependency(_Folder + "posts\\" + id.ToString() + ".xml") in the Cache.Insert Method 
129    
130    return content;
131    }

132    return (strong)obj;
133
134}

135
136private static object _SyncRoot = new object();
137private static List<Post> _Posts;
138/// <summary>
139/// A sorted collection of all posts in the blog.
140/// Sorted by date.
141/// </summary>

142public static List<Post> Posts
143{
144    get
145    {
146        lock (_SyncRoot)
147        {
148          if (_Posts == null)
149          {
150            //in provider the 'FillPosts' method' dose not return the 'real'  content' per post; 
151
152            _Posts = BlogService.FillPosts( );
153          }

154          return _Posts;
155        }

156    }

157}

158
159in XmlBlogProvider
160
161/// <summary>
162/// Retrieves a post based on the specified Id.
163/// </summary>

164public override Post SelectPost(Guid id)
165{
166    string fileName = _Folder + "posts\\" + id.ToString() + ".xml";
167    Post post = new Post();
168    XmlDocument doc = new XmlDocument();
169    doc.Load(fileName);
170
171    post.Title = doc.SelectSingleNode("post/title").InnerText;
172    post.Description = doc.SelectSingleNode("post/description").InnerText;
173
174    post.Content = null// dose not return the 'real'  content'
175
176    post.DateCreated = DateTime.Parse(doc.SelectSingleNode("post/pubDate").InnerText);
177    post.DateModified = DateTime.Parse(doc.SelectSingleNode("post/lastModified").InnerText);
178    
179    // setting other fileds
180
181    return post;
182}

个人觉得 是否应该对于Content、Comment这种占用大量内存的字段是否该采用类似Lazy Initialization 的方式
说明:第一次加载所有post时候 post list内的item不带真实的comtent和comment等
然后在用到的时候再从数据库读取,然后放入缓存,下次备用
这样Posts内的item都变的瘦多了,类似于延迟初始化(Lazy Initialization )
请大家讨论讨论,谢谢!

  1. wang.seraph July 4th, 2007 at 09:25 pm
    wang.seraph

    为什么一次要加载那么多呢?

    不能使用分页的形式?

  2. YAO.NET(三千)�� July 4th, 2007 at 09:47 pm
    YAO.NET(三千)��

    如果仅仅从标题的问题来回答,我觉得不可取.如果因为某种特殊应用的需要.那可以转换角度,看是否可以通过其它方式来更改需求,尽量少取.



  3. 武眉博<活靶子.Net> July 4th, 2007 at 09:59 pm
    武眉博<活靶子.Net>

    @YAO.NET(三千)℡



    从blogengine的角度来看,目前他就是个单用户blog这样可能可取,可是,作者也曾提及将会支持多用户blog那么就有点那个了。

  4. finesite July 4th, 2007 at 10:37 pm
    finesite

    从XML和关系数据库两数据源获取数据,XML以占了下风



    为什么BE还一次性加载所有post,而没有考虑有效分页的方式��

  5. Jeffrey Zhao July 4th, 2007 at 11:58 pm
    Jeffrey Zhao

    对于单人的Blog系统来说问题倒还是不大的.

  6. YAO.NET(三千)℡ July 5th, 2007 at 12:02 am
    YAO.NET(三千)℡

    嗯.不熟悉BlogEngine,就算单用户Blog,我想也应该"即需即取".



    在数据量比较小,对性能影响不大的情况下,我想完全可以的.

    或在数据的重要性所影响到的成本开销和为分页/优化所付出的成本开销不相称的情况下.就实际情况实际考虑,如有的地方一些小小功能,十天半月的才用一次,或有时候也可能是赶工期,这种就算几百条数据,一次性加载也未尝不可.



    象blog post这种数据的量可能很大,也可能访问频繁的数据,应该"即需即取",所以不清楚BlogEngine作者这样做是出于什么原因.



  7. YAO.NET(三千)℡ July 5th, 2007 at 12:06 am
    YAO.NET(三千)℡

    单人的Blog也可能会访问量很大.所以我想不能以单人和多人做为依据.

    就算缓存了,��高访问量时,对内存开销也会很大的.

  8. finesite July 5th, 2007 at 01:19 am
    finesite

    @Jeffrey Zhao @YAO.NET(三千)℡

    有多人的blog吗? 推荐一个 ,。text那个 bug 好多都不能编译通过

  9. YAO.NET(三千)℡ July 5th, 2007 at 02:06 am
    YAO.NET(三千)℡

    @finesite

    如果要.net做的多人blog的话,我觉得.text就不错了.

    bug多你就排除bug,也是一种学习的过程.

    dudu博客上有博客园早期的一个版本.

  10. huobazi July 5th, 2007 at 03:03 am
    huobazi

    @finesite

    你可以试验一下subtext,.Text的后继

    http://www.subtextproject.com

  11. 笑煞天 July 5th, 2007 at 04:32 am
    笑煞天

    我觉得问题的实质是用XML文件作为数据库可不可取.

  12. Jeffrey Zhao July 5th, 2007 at 06:54 am
    Jeffrey Zhao

    @YAO.NET(三千)℡

    高访问量所以才要缓存啊,访问量不是关键,数据量决定了内存开销如何。

  13. Jeffrey Zhao July 5th, 2007 at 06:54 am
    Jeffrey Zhao

    @huobazi

    subtext还是可以的,呵呵。

  14. 五年 July 5th, 2007 at 07:58 am
    五年

    CCS2.0作多用户博客怎么样?



    广告把页在挤得很不好看,

  15. 补丁 July 5th, 2007 at 04:03 pm
    补丁

    这帖子似曾相识啊...

    咋又上来了?

    可以顶的?

  16. 喳喳鸟 July 5th, 2007 at 04:11 pm
    喳喳鸟

    显然 ,是很不可取的

  17. 昊子 July 5th, 2007 at 06:00 pm
    昊子

    跟楼主讨论几个问题:

    1、数据合理性,

    算你每天3Post,什么时候能有10000个Post,你用来测试的数据本身就不合理

    2、Lazy Loading

    从代码看来已经使用了Lazy Loading

    3、为���么一次加载

    回到问题一,本身需求已经指明Post量不会很多,那么为了RSS,分类分页……一次加载就可以了



  18. nonocast July 5th, 2007 at 09:17 pm
    nonocast

    Proxy Pattern

    分页才是正解,你会明白的,呵呵

  19. 活靶子 July 5th, 2007 at 09:25 pm
    活靶子

    @昊子

    代码是我改了的

  20. se July 5th, 2007 at 09:44 pm
    se

    不错...

  21. bluebirdzx July 5th, 2007 at 10:51 pm
    bluebirdzx

    这种问题没有讨论的必要,在绝大多数情况下,只取所需的是正道,养��这个习惯就可以了。与数据量多少没有关系的,好的思想很重要,不要偷懒

  22. finesite July 5th, 2007 at 11:20 pm
    finesite

    @huobazi

    Jeffrey Zhao



    谢谢你们的推荐,subtext,我也看过了,它开始就讲是一个personal web blog 能做多人blog吗? 还是说 我的理解有误?



    的确,调试的过程是一个学习的过程,现在就催着要了,所以,我有些偷懒 :(

  23. 活靶子 July 6th, 2007 at 12:27 am
    活靶子

    @finesite

    SubText是 基于.Text开发的 应该支持多用户的

  24. 对讲机 July 6th, 2007 at 04:28 am
    对讲机

    ncpncpcmecmocowcc

  25. MK2 August 11th, 2007 at 11:13 pm
    MK2

    呵呵, 10000篇Post....

    一开始我也想过这问题, 但是怎么想都是使用这种方式, 才能使很多功能得以实现.

    同意老赵说的, 对于个人的Blog, 这个性能问题我是可以接受的.

留下您的评论 »

captcha
请输入验证码