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>
72
public 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
}
91
Post class in Business object layer
92
93
private string _Content;
94
/**//// <summary>
95
/// Gets or sets the Content or the post.
96
/// </summary>
97
public 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
}
114
private 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
136
private static object _SyncRoot = new object();
137
private 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}
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
57
58 //in provider the 'FillPosts' method' dose not return the 'real' content' per post;
59
60
61 }
62 return _Posts;
63 }
64 }
65}
66
67in XmlBlogProvider
68
69/**//// <summary>
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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 )
请大家讨论讨论,谢谢!
为什么一次要加载那么多呢?
不能使用分页的形式?
如果仅仅从标题的问题来回答,我觉得不可取.如果因为某种特殊应用的需要.那可以转换角度,看是否可以通过其它方式来更改需求,尽量少取.
@YAO.NET(三千)℡
从blogengine的角度来看,目前他就是个单用户blog这样可能可取,可是,作者也曾提及将会支持多用户blog那么就有点那个了。
从XML和关系数据库两数据源获取数据,XML以占了下风
为什么BE还一次性加载所有post,而没有考虑有效分页的方式��
对于单人的Blog系统来说问题倒还是不大的.
嗯.不熟悉BlogEngine,就算单用户Blog,我想也应该"即需即取".
在数据量比较小,对性能影响不大的情况下,我想完全可以的.
或在数据的重要性所影响到的成本开销和为分页/优化所付出的成本开销不相称的情况下.就实际情况实际考虑,如有的地方一些小小功能,十天半月的才用一次,或有时候也可能是赶工期,这种就算几百条数据,一次性加载也未尝不可.
象blog post这种数据的量可能很大,也可能访问频繁的数据,应该"即需即取",所以不清楚BlogEngine作者这样做是出于什么原因.
单人的Blog也可能会访问量很大.所以我想不能以单人和多人做为依据.
就算缓存了,��高访问量时,对内存开销也会很大的.
@Jeffrey Zhao @YAO.NET(三千)℡
有多人的blog吗? 推荐一个 ,。text那个 bug 好多都不能编译通过
@finesite
如果要.net做的多人blog的话,我觉得.text就不错了.
bug多你就排除bug,也是一种学习的过程.
dudu博客上有博客园早期的一个版本.
@finesite
你可以试验一下subtext,.Text的后继
http://www.subtextproject.com
我觉得问题的实质是用XML文件作为数据库可不可取.
@YAO.NET(三千)℡
高访问量所以才要缓存啊,访问量不是关键,数据量决定了内存开销如何。
@huobazi
subtext还是可以的,呵呵。
CCS2.0作多用户博客怎么样?
广告把页在挤得很不好看,
这帖子似曾相识啊...
咋又上来了?
可以顶的?
显然 ,是很不可取的
跟楼主讨论几个问题:
1、数据合理性,
算你每天3Post,什么时候能有10000个Post,你用来测试的数据本身就不合理
2、Lazy Loading
从代码看来已经使用了Lazy Loading
3、为���么一次加载
回到问题一,本身需求已经指明Post量不会很多,那么为了RSS,分类分页……一次加载就可以了
Proxy Pattern
分页才是正解,你会明白的,呵呵
@昊子
代码是我改了的
不错...
这种问题没有讨论的必要,在绝大多数情况下,只取所需的是正道,养��这个习惯就可以了。与数据量多少没有关系的,好的思想很重要,不要偷懒
@huobazi
Jeffrey Zhao
谢谢你们的推荐,subtext,我也看过了,它开始就讲是一个personal web blog 能做多人blog吗? 还是说 我的理解有误?
的确,调试的过程是一个学习的过程,现在就催着要了,所以,我有些偷懒 :(
@finesite
SubText是 基于.Text开发的 应该支持多用户的
ncpncpcmecmocowcc
呵呵, 10000篇Post....
一开始我也想过这问题, 但是怎么想都是使用这种方式, 才能使很多功能得以实现.
同意老赵说的, 对于个人的Blog, 这个性能问题我是可以接受的.