在.NET中是否存在用于长时间运行线程的线程调度程序?

我们的场景是网络扫描仪。

它连接到一组主机并使用低优先级后台线程并行扫描它们一段时间。

我希望能够安排大量工作,但只有任何给定的说十个或同时扫描的任何数量的主机。 即使我创建自己的线程,许多回调和其他异步善良使用ThreadPool,我最终耗尽资源。 我应该看一下MonoTorrent ……

如果我使用ThreadPool,我可以将我的应用程序限制为某个数字,这些数字将足以让应用程序的其余部分顺利运行吗?

是否有一个线程池,我可以初始化为n长寿线程?

[编辑]似乎没有人注意到我对一些回复做了一些评论,所以我会在这里添加一些东西。

  • 线程应该可以优雅和有力地取消。
  • 线程应具有低优先级,使GUI响应。
  • 线程长时间运行,但是按顺序(分钟)而不是订单(天)。

针对给定目标主机的工作基本上是:

For each test Probe target (work is done mostly on the target end of an SSH connection) Compare probe result to expected result (work is done on engine machine) Prepare results for host 

有人可以解释为什么使用SmartThreadPool标记有消极的用处吗?

在.NET 4中,您拥有集成的任务并行库 。 创建新任务(新线程抽象)时,可以指定要长时间运行的任务。 我们已经取得了很好的经验(长期是几天而不是几分钟或几小时)。

您也可以在.NET 2中使用它,但它实际上是一个扩展,请在此处查看

在VS2010中,基于任务(而非线程)的调试并行应用程序得到了彻底改进 。 建议尽可能使用Tasks而不是原始线程。 因为它允许您以更加面向对象的友好方式处理并行性。

UPDATE
未指定为长时间运行的任务将排队到线程池(或任何其他调度程序)中。
但是如果指定一个任务长时间运行 ,它只创建一个独立的线程不涉及任何线程池

CLR ThreadPool不适合执行长时间运行的任务:它用于执行短任务,其中创建线程的成本几乎与执行方法本身一样高。 (或者至少占执行该方法所花费的时间的很大一部分。)正如您所见,.NET本身消耗线程池线程,您不能为自己保留它们的块,以免冒着运行时的风险。

调度,限制和取消工作是另一回事。 没有其他内置的.NET工作队列线程池,所以你将自己滚动(自己管理线程或BackgroundWorkers )或找到一个预先存在的线程池( Ami Bar的SmartThreadPool看起来很有前景,尽管我自己没有使用它)。

在您的特定情况下,最佳选项不是线程或线程池或后台工作程序,而是框架提供的异步编程模型(BeginXXX,EndXXX)。

使用异步模型的优点是,只要有数据要读取,TcpIp堆栈就会使用回调,并且回调会自动在线程池的线程上运行。

使用异步模型 ,您可以控制每个启动时间间隔的请求数量,如果您需要,您可以在处理普通优先级线程上的请求时启动来自较低优先级线程的所有请求,这意味着数据包将保持尽可能少可能在网络堆栈的内部Tcp队列中。

异步客户端套接字示例 – MSDN

PS对于多个并发和长时间运行的作业,它们不进行大量计算但主要等待IO(网络,磁盘等),更好的选择始终是使用回调机制而不是线程。

我会创建自己的线程管理器。 在下面的简单示例中,Queue用于保存等待线程,而Dictionary用于保存活动线程,由ManagedThreadId键入。 线程完成后,它会从活动字典中删除自己,并通过回调启动另一个线程。

您可以从UI更改最大运行线程限制,并且可以将额外信息传递给ThreadDone回调以监视性能等。如果线程失败,例如网络超时,则可以重新插入队列。 向Supervisor添加额外的控制方法,用于暂停,停止等。

 using System; using System.Collections.Generic; using System.Threading; namespace ConsoleApplication1 { public delegate void CallbackDelegate(int idArg); class Program { static void Main(string[] args) { new Supervisor().Run(); Console.WriteLine("Done"); Console.ReadKey(); } } class Supervisor { Queue waitingThreads = new Queue(); Dictionary activeThreads = new Dictionary(); int maxRunningThreads = 10; object locker = new object(); volatile bool done; public void Run() { // queue up some threads for (int i = 0; i < 50; i++) { Thread newThread = new Thread(new Worker(ThreadDone).DoWork); newThread.IsBackground = true; waitingThreads.Enqueue(newThread); } LaunchWaitingThreads(); while (!done) Thread.Sleep(200); } // keep starting waiting threads until we max out void LaunchWaitingThreads() { lock (locker) { while ((activeThreads.Count < maxRunningThreads) && (waitingThreads.Count > 0)) { Thread nextThread = waitingThreads.Dequeue(); activeThreads.Add(nextThread.ManagedThreadId, nextThread); nextThread.Start(); Console.WriteLine("Thread " + nextThread.ManagedThreadId.ToString() + " launched"); } done = (activeThreads.Count == 0) && (waitingThreads.Count == 0); } } // this is called by each thread when it's done void ThreadDone(int threadIdArg) { lock (locker) { // remove thread from active pool activeThreads.Remove(threadIdArg); } Console.WriteLine("Thread " + threadIdArg.ToString() + " finished"); LaunchWaitingThreads(); // this could instead be put in the wait loop at the end of Run() } } class Worker { CallbackDelegate callback; public Worker(CallbackDelegate callbackArg) { callback = callbackArg; } public void DoWork() { System.Threading.Thread.Sleep(new Random().Next(100, 1000)); callback(System.Threading.Thread.CurrentThread.ManagedThreadId); } } } 

使用内置线程池。 它具有良好的能力。

或者,您可以在此处或在扩展线程池中查看智能线程池实现 ,以限制最大工作线程数。