当前位置: 代码迷 >> C# >> 大家帮忙看看这个业务该怎么办?
  详细解决方案

大家帮忙看看这个业务该怎么办?

热度:102   发布时间:2016-05-05 05:24:20.0
大家帮忙看看这个业务该怎么处理??


需求是这样的:
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 线程空闲时(可以用来显示时)才会调用它。
  相关解决方案