我有一个.NET 3.5 Windows服务。我正在使用一个小应用程序进行测试,该应用程序在启动后只是睡眠线程,随机时间跨度为300到6500毫秒。关于这个问题,我有各种各样的问题。
BackgroundWorker
是否真的只适合在WinForms应用程序中使用,或者这只是无意义,它究竟是如何调整到这种效果的?ThreadPool
s。我不确定线程会持续半秒到几秒之间的问题对我来说有多大问题。这个理由足以让人看到其他地方吗?真实服务将轮询数据库中的待处理请求列表,为每个请求执行线程(限于一定数量的并发线程),每个线程将检查数据库中是否存在某些数据,如果是,则检索它,或者从流API下载它,存储它,并返回该数据。下载将是消耗最多时间的部分。
我真的希望在.NET 3.5 Framework中回答这个问题,但如果在.NET 4.0下有更好或更有效的方法来实现这一点,我也想了解它们。更多信息的链接也非常受欢迎。
答案 0 :(得分:34)
BackgroundWorker
中的值是它可以在创建其实例的线程上引发其ProgressChanged
和RunworkerCompleted
事件。这使得非常在不支持免费线程的程序中非常方便。
为了使其正常工作,需要SynchronizationContext.Current
属性引用非默认同步提供程序。一个提供程序,负责将调用从一个线程调用到另一个线程。 .NET框架有两个随时可用的提供程序:System.Windows.Forms.WindowsFormsSynchronizationContext
和System.Windows.Threading.DispatcherSynchronizationContext
。这些提供程序分别处理Winforms和WPF的同步。
有一个连接,Winforms和WPF都是具有线程问题的类库。实现GUI和基于Windows的图形用户界面都基本上是线程不安全的。 Windows窗口只能从创建它们的线程更新。换句话说,存在这些自定义同步提供程序,因为它们非常需要它们。另外值得注意的是,它们通过利用UI线程的工作方式来工作。 UI线程以事件驱动的方式执行代码,抽取消息循环以接收通知。同步提供程序可以使用此机制向事件处理程序注入调用。这不是偶然的。
回到主题,Windows服务没有这样的功能。它没有GUI,也没有安装自定义同步提供程序。因此,BackgroundWorker
不提供在服务中有用的功能。如果没有自定义同步提供程序,默认提供程序只会在线程池线程上运行事件。哪个没用,你可以从工作线程中激活事件。除非您重新创建消息循环机制或挂钩到Winforms管道并使用不可见窗口创建模拟UI线程,否则很难实现在另一个特定线程上运行事件。这不是完全不常见的。
答案 1 :(得分:10)
BackgroundWorker旨在简化后台线程中工作的任务与UI的交互。您将看到关于何时使用BackGroundWorker,ThreadPool以及在BackgroundWorker vs background Thread
处简单线程的最佳答案我认为它回答了问题:)。
答案 2 :(得分:9)
我写了一篇关于异步后台任务on my blog的各种实现的相当详尽的概述。摘要是:prefer Task
;第二个选择是BackgroundWorker
;如果您确实需要,则只能使用Thread
或ThreadPool.QueueUserWorkItem
。
理由:检测错误并从错误中恢复更容易,并且更容易同步回UI。
回答您的具体问题:
BackgroundWorker
适用于任何主机,包括WinForms和WPF(甚至是ASP.NET!),因为it is based on SynchronizationContext
。 Windows服务没有SynchronizationContext
,但您可以使用Nito.Async library中的ActionThread
SynchronizationContext
。
如果我正确阅读了您的问题,您目前有Thread
个问题,正在考虑ThreadPool
和BackgroundWorker
。在这些选择中,我建议使用BackgroundWorker
,但如果有机会,请在.NET 4.0中使用新的Task
类(如果安装Microsoft Rx,也可以使用Task
。 NET 3.5)。
答案 3 :(得分:3)
绝对不是服务的后台工作者
你应该使用System.Threading.Tasks命名空间中的Tasks,也可以使用任务并行线程执行
http://msdn.microsoft.com/en-us/library/dd460717.aspx
我引用:“从.NET Framework 4开始,TPL是编写多线程和并行代码的首选方式。”
一些读物:
http://msdn.microsoft.com/en-us/library/dd997413%28VS.100%29.aspx
从这里开始:
http://msmvps.com/blogs/brunoboucard/archive/2010/04/09/parallel-programming-task-oriented-parallel-part-1.aspx
http://msmvps.com/blogs/brunoboucard/archive/2010/05/18/parallel-programming-in-c-4-0-task-oriented-parallel-programming-part-2.aspx
http://msmvps.com/blogs/brunoboucard/archive/2010/11/06/parallel-programming-with-c-4-0-part-3.aspx
更多例子
http://www.dotnetcurry.com/ShowArticle.aspx?ID=489
http://www.dotnetfunda.com/articles/article984-parallel-compting-in-csharp-40-.aspx
答案 4 :(得分:2)
我认为你的第三选择是最好的。我在.Net 3.5中使用Windows服务做了类似的事情,发现创建自己的线程是一个很好的方法,特别是对于与Web服务连接的线程。
我创建了一个工作者实例,并给它一个回调函数,在服务完成时发出信号。我将准备好运行的线程存储在Queue
中,并根据我想要的最大并发线程数剥离它们。如果你关心的只是运行服务的数量,你可以用一个简单的计数器跟踪它们。我更喜欢将每个正在运行的工作者实例存储在由线程Dictionary
键入的ManagedThreadId
中,以便我可以轻松地向每个实例发出信号,如果我想要干净地关闭它。轮询正在运行的实例以检查状态也很方便。