multithreading服务,BackgroundWorker与ThreadPool?

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

  1. BackgroundWorker是否真的只适用于WinForms应用程序,或者这只是废话,究竟是如何调整到这种效果的呢?
  2. 我已经在这个问题和这个 问题中读到了关于ThreadPool的内容。 我不确定线程​​会持续半秒到几秒之间的问题对我来说有多大问题。 这个理由足以让人看到其他地方吗?
  3. 我自己最好只创建后台线程吗?

现实生活中的服务将轮询数据库中的待处理请求列表,为每个请求执行线程(限于一定数量的并发线程),每个线程将检查数据库中是否存在某些数据,如果它可以,或从流API下载,存储它,并返回该数据。 下载将是消耗最多时间的部分。

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

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

为使其正常工作,需要SynchronizationContext.Current属性引用非默认同步提供程序。 负责将调用从一个线程封送到另一个线程的提供程序。 .NET框架有两个随时可用的提供程序: System.Windows.Forms.WindowsFormsSynchronizationContextSystem.Windows.Threading.DispatcherSynchronizationContext 。 这些提供程序分别处理Winforms和WPF的同步。

有一个连接,Winforms和WPF都是具有线程问题的类库。 实现GUI和基于Windows的图形用户界面都基本上是线程不安全的。 Windows窗口只能从创建它们的线程更新。 换句话说,存在这些自定义同步提供程序,因为它们非常需要它们。 另外值得注意的是,它们通过利用UI线程的工作方式来工作。 UI线程以事件驱动的方式执行代码,抽取消息循环以接收通知。 同步提供程序可以使用此机制向事件处理程序注入调用。 这不是偶然的。

回到主题,Windows服务没有这样的function。 它没有GUI,也没有安装自定义同步提供程序。 因此, BackgroundWorker不提供在服务中有用的function。 如果没有自定义同步提供程序,默认提供程序只会在线程池线程上运行事件。 哪个没用,你可以从你的工作线程中激活事件。 除非您重新创建消息循环机制或挂钩到Winforms管道并使用不可见窗口创建模拟UI线程,否则很难实现在另一个特定线程上运行事件。 这不是完全不常见的顺便说一句。

BackgroundWorker旨在简化后台线程中工作的任务与UI的交互。 您将看到关于何时使用BackGroundWorker,ThreadPool以及在BackgroundWorker和后台线程中使用Thread的简单答案

我认为它回答了问题:)。

我在博客上写了一篇关于异步后台任务的各种实现的相当详尽的概述。 总结是:prefer Task ; 第二个选择是BackgroundWorker ; 如果你真的需要 ,只使用ThreadThreadPool.QueueUserWorkItem

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

回答您的具体问题:

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

如果我正确地读了你的问题,你现在有了Thread并且正在考虑ThreadPoolBackgroundWorker 。 在这些选择中,我推荐BackgroundWorker ,但如果有机会,请在.NET 4.0中使用新的Task类(如果安装Microsoft Rx,也可以使用.NET 3.5中的Task )。

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

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