如何在System.Threading.Tasks.Parallel-loop

时间:2017-12-12 12:35:02

标签: c# wpf multithreading

首先,我必须猜测我对异步没什么经验。

我在WPF应用程序上使用VS2015,我有一个面具设计师。 在那里,我可以通过拖放操作向画布添加控件,移动和调整它们的大小。 大小和位置的变化临时存储在字典中,稍后通过单击“保存”按钮保存到数据库中。

为了优化更新的速度,我认为用异步System.Threading.Tasks.Parallel.ForEach替换同步foreach会很好。 但现在我遇到了问题,我不能使用一些WPF控件 - 比如控件所在的画布 - 在该循环中,因为它们属于主线程。

如何在循环中访问这些控件?

以下是我的代码中的经验,这使我在这个时间点出现问题:

Parallel.ForEach(ChangedElements, (changedElement) =>
{
    FrameworkElement element = elementHelper.GetElementFromPanel(changedElement.Value, designerwindow.maskDesignerPanel);
    elementHelper.UpdateElementPositionAndSize(element, designerwindow, inputFieldList);
});

“ChangedElements”是包含已更改的WPF元素名称的字典。 最初它是类型但我改为它所以键和值包含控件的名称/标识符。 “designerWindow”是对WPF窗口的引用和“maskDesignerPanel”画布的名称。 在运行时,当我尝试从画布的子集合中获取元素时,我在GetElementFromPanel方法中出现错误。 在这种情况下,我无法访问子集合,因为它属于主线程。

这里是GetElementFromPanel方法的代码:

    public FrameworkElement GetElementFromPanel(string elementName, Canvas panel)
    {
        FrameworkElement element = null;

        foreach (FrameworkElement child in panel.Children)
        {
            if (child.Name == elementName)
            {
                element = child;
                break;
            }
        }

        return element;
    }

1 个答案:

答案 0 :(得分:2)

<强> UPD 如果你有数以千计的元素和高频率的更新快速而廉价的方法来加速GetElementFromPanel:将所有元素放入Dictionary&lt;,&gt;通过唯一的名称密钥,所以您不必每次都扫描所有孩子。

关于多线程

  1. 在进行优化之前,您应该使用分析器证明您的假设,代码的哪一部分很重?
  2. 如果您发现UI的更新速度很慢,则无需进行多线程处理(所有线程都将等待主UI线程)
  3. 如果你看到算法的某些部分很慢,那么优化它(不是UI交互,我的意思是算法)
  4. 只需将重型代码推出UI
  5. 如果算法仍然很慢,请确保算法可并行化,如果是这样,您可以采用以下方法之一:
  6. 一个。 Dispatcher.Invoke方法:只运行一些刷新ui的代码 https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke(v=vs.110).aspx

    湾使用生成器 - 消费者模式与BlockingCollection类似。 推送数据进行处理,处理一些线程,然后将结果推送到主线程中以显示结果   https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/blockingcollection-overview

    ℃。使用反应式编程 https://msdn.microsoft.com/en-us/library/hh242985(v=vs.103).aspx

    d。如果你想删除ui冻结,请直接使用async / await或TPL来运行UI线程的大量代码。

    ....许多其他方式

    在进行多线程处理之前,最好解开并拆分ui-get部分,处理部分和ui-refresh部分代码。