
需求是这样的:
1:左边dgv的每一行对应一棵树,点击任何一个单元格,都会更新其所属的棵树
问题:
1:由于更新操作需要发起web请求,构建treeview,所以可能比较耗时,所以用的是后台任务
用了后台任务出现了下面这些问题:
1:只要鼠标点到一个单元格,就会创建一个后台任务,当用户一次点击到多个的时候,这棵树更新会很慢
2:而且是多线程,所以这棵树的结果很可能是错误的(加锁会照成树更新更慢)(这个问题暂时用的是每个后台任务一个临时treeview)
3:多次的不必要的后台任务,造成远程服务器不必要的压力
开始想用缓存,但是缓存在保证本地数据和远程数据的一致性上做不好,而且可能更麻烦。
------解决思路----------------------
由于更新操作需要发起web请求,构建treeview
创建treeview要发起web请求??什么道理
------解决思路----------------------
如果“点击单元格,只加载一层节点”,这才是比较灵活的。
即使是需要加载整个子树,对于你的第2点,它也不能胡乱加锁。仅仅在必要的地方加锁。例如
static void ExpandAsync(TreeNode parent, string id)
{
ThreadPool.QueueUserWorkItem(h =>
{
List<string> lst = CallWebService(id);
List<TreeNode> nodes = 创建TreeNode(lst);
lock (parent.TreeView)
{
for (var i = 0; i < lst.Count; i++)
{
var n = nodes[i];
parent.Nodes.Add(n);
ExpandAsync(n, lst[i]);
}
}
});
}
这里,当执行 ExpandAsync(n, lst[i]); 的时候,实际上已经在另外一个子线程了,跳出了 lock 的范围。
而如果你只是一个线程内去执行所有的 CallWebService 语句,那么显然不行,那样你的 lock 显然是会卡住自己的。
当然你写
static void ExpandAsync(TreeNode parent, string id)
{
ThreadPool.QueueUserWorkItem(h =>
{
List<string> lst = CallWebService(id);
List<TreeNode> nodes = 创建TreeNode(lst);
parent.TreeView.BeginInvoke((Action)delegate
{
for (var i = 0; i < lst.Count; i++)
{
var n = nodes[i];
parent.Nodes.Add(n);
ExpandAsync(n, lst[i]);
}
});
});
}
会更好。因为这里不用什么 lock,在 UI 线程空闲时(可以用来显示时)才会调用它。