多线程服务,BackgroundWorker与ThreadPool?

时间:2011-07-08 15:56:02

标签: c# .net multithreading windows-services

我有一个.NET 3.5 Windows服务。我正在使用一个小应用程序进行测试,该应用程序在启动后只是睡眠线程,随机时间跨度为300到6500毫秒。关于这个问题,我有各种各样的问题。

  1. BackgroundWorker是否真的只适合在WinForms应用程序中使用,或者这只是无意义,它究竟是如何调整到这种效果的?
  2. 我在this questionthis one中了解过ThreadPool s。我不确定线程​​会持续半秒到几秒之间的问题对我来说有多大问题。这个理由足以让人看到其他地方吗?
  3. 我自己最好只创建后台线程吗?
  4. 真实服务将轮询数据库中的待处理请求列表,为每个请求执行线程(限于一定数量的并发线程),每个线程将检查数据库中是否存在某些数据,如果是,则检索它,或者从流API下载它,存储它,并返回该数据。下载将是消耗最多时间的部分。

    我真的希望在.NET 3.5 Framework中回答这个问题,但如果在.NET 4.0下有更好或更有效的方法来实现这一点,我也想了解它们。更多信息的链接也非常受欢迎。

5 个答案:

答案 0 :(得分:34)

BackgroundWorker中的值是它可以在创建其实例的线程上引发其ProgressChangedRunworkerCompleted事件。这使得非常在不支持免费线程的程序中非常方便。

为了使其正常工作,需要SynchronizationContext.Current属性引用非默认同步提供程序。一个提供程序,负责将调用从一个线程调用到另一个线程。 .NET框架有两个随时可用的提供程序:System.Windows.Forms.WindowsFormsSynchronizationContextSystem.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;如果您确实需要,则只能使用ThreadThreadPool.QueueUserWorkItem

理由:检测错误并从错误中恢复更容易,并且更容易同步回UI。

回答您的具体问题:

BackgroundWorker适用于任何主机,包括WinForms和WPF(甚至是ASP.NET!),因为it is based on SynchronizationContext。 Windows服务没有SynchronizationContext,但您可以使用Nito.Async library中的ActionThread SynchronizationContext

如果我正确阅读了您的问题,您目前有Thread个问题,正在考虑ThreadPoolBackgroundWorker。在这些选择中,我建议使用BackgroundWorker,但如果有机会,请在.NET 4.0中使用新的Task类(如果安装Microsoft Rx,也可以使用Task。 NET 3.5)。

答案 3 :(得分:3)

答案 4 :(得分:2)

我认为你的第三选择是最好的。我在.Net 3.5中使用Windows服务做了类似的事情,发现创建自己的线程是一个很好的方法,特别是对于与Web服务连接的线程。

我创建了一个工作者实例,并给它一个回调函数,在服务完成时发出信号。我将准备好运行的线程存储在Queue中,并根据我想要的最大并发线程数剥离它们。如果你关心的只是运行服务的数量,你可以用一个简单的计数器跟踪它们。我更喜欢将每个正在运行的工作者实例存储在由线程Dictionary键入的ManagedThreadId中,以便我可以轻松地向每个实例发出信号,如果我想要干净地关闭它。轮询正在运行的实例以检查状态也很方便。