在我的WPF应用程序中,我需要进行异步操作,然后我需要更新GUI。这件事我不得不在不同的时刻做不同的操作。我知道两种方法:Dispatcher和BackgroundWorker。
因为当我选择它时我会很难回去,我问你:什么更好?选择一个而不是另一个的原因是什么?
谢谢! Pileggi
答案 0 :(得分:37)
Dispatcher和其他线程方法之间的主要区别在于Dispatcher实际上并不是多线程的。 Dispatcher控制控件,这需要一个线程才能正常运行; Dispatcher的BeginInvoke方法将事件排队等待以后执行(取决于优先级等),但仍然在同一个线程上。
另一方面,BackgroundWorker实际上是在一个单独的线程中调用它的同时执行代码。它也比真正的线程更容易使用,因为它自动同步(至少我认为我记得这个)与应用程序的主线程,负责控件和消息队列(在WPF的情况下为Dispatcher线程) Silverlight),所以在从后台线程更新控件时不需要使用Dispatcher.Invoke(或WinForms中的Control.Invoke),尽管可能并不总是建议这样做。正如里德所说,任务并行库是一个很好的选择。
编辑:进一步的观察。
正如我上面所说,Dispatcher并不是真正的多线程;它只会给出它的错觉,因为它会运行你在另一个时间传递给它的委托。我只在代码真正处理应用程序的View方面时才使用Dispatcher,即控件,页面,窗口以及所有这些。当然,它的主要用途实际上是触发来自其他线程的操作,以正确地或在正确的时间更新控件(例如,只有在某些控件完全呈现/布局后才设置焦点最多使用Dispatcher很容易实现,因为在WPF中渲染并不完全是确定性的。)
BackgroundWorker可以使多线程代码比通常情况简单得多;这是一个简单的概念,最重要的是(如果有意义的话)你可以从中派生自定义工作者,它可以是异步执行单个任务的专用类,具有可用作参数,进度通知和取消等的属性我总是发现BackgroundWorker是一个巨大的帮助(除非我必须从中得到它以保持原始线程的文化以保持正确的本地化:P)
最强大但也很难的路径是使用最低级别的System.Threading.Thread;但是,如果出现问题那么容易出错,并不是真的值得推荐。多线程编程是 hard ,这是给定的。但是,如果你想了解所有方面的话,有很多很好的信息:this excellent article由我们的好伙伴Jon Skeet立即跳到脑海中(文章的最后一页也有很多非常有趣的链接)
在.Net 4.0中,我们有一个不同的选项,即任务并行库。我还没有使用它,但是从我看到的它令人印象深刻(PLINQ简直太棒了)。如果你有好奇心和资源来学习它,那就是我的建议(毕竟不应该那个很多东西)。
答案 1 :(得分:8)
如果您正在执行单个操作,它提供进度通知和完成事件,那么BackgroundWorker很不错。但是,如果您要多次运行相同的操作或多次操作,那么您将需要多个BackgroundWorker。在这种情况下,它可能会很麻烦。
如果您不需要进度事件,那么使用ThreadPool和Dispatcher可以更简单 - 特别是如果您要进行相当多的不同操作。
如果C#4是一个选项,那么使用任务并行库也是一个很好的选择。这使您可以使用当前的SynchronizationContext设置继续任务,在许多情况下,它提供了更简单,更简洁的模型。有关详细信息,请参阅有关主题的my blog post。