如何获得第二个System.Thread.ThreadPool?

如果我以嵌套的方式使用ThreadPool,我的应用程序会挂起:

ThreadPool.QueueUserWorkItem((state) => ThreadPool.QueueUserWorkItem(Action)); 

如何获得第二个独立的ThreadPool来实现嵌套?

只有一个ThreadPool – 它不是你可以(或应该)在应用程序中创建多个实例的东西。

我不建议这样做,但如果你真的想,你可以使用自己的ThreadPool实现的多个实例,例如SmartThreadPool 。 从技术上讲,这将允许单独的“线程池”。

但是,我怀疑你因为死锁而挂起,而不是由于ThreadPool的使用。 我会调查你在哪里挂起。 如果您安装了VS 2010 beta的副本,VS2010并发可视化器非常适合。

您的应用程序可能正在挂起,因为您正在填充它,直到所有活动线程都在排队的线程上等待。 (我假设原始线程正在等待它排队完成的工作项。)

ThreadPool默认具有25 *(CPU数)工作线程(IIRC)。

您可能想要按照排队项目的方式进行返工。 如果你把它们排队然后完成并退出线程,那你很好,但是等待其他进程的工作项目通常是一个糟糕的设计; 如果你正在做的事情,你可能需要使用真正的线程或完全不同的设计。 使用真正的线程可能是一个同样糟糕的主意,因为所有这些(基于我可以猜测你的用法)你只会创建大量的线程,这对你的性能没有任何好处。

一个更好的设计可能是拥有某种类型的队列或堆栈,少数(2-4个取决于CPU的数量)工作线程添加项目并弹出项目工作。 如果一个项目需要对一个新项目进行排队,它只需将它添加到堆栈中(如果需要等待另一个项目,则将其自身添加回堆栈,并进行某种依赖性跟踪)。

您使用的是错误的工具。

在.NET 4.0中,他们引入了任务并行库。 这允许您执行诸如使用多个thead池以及在工作项之间具有父子关系的操作。

从Task类开始,它替换ThreadPool.QueueUserWorkItem。

http://msdn.microsoft.com/en-us/library/system.threading.tasks.task(VS.100).aspx

编辑

使用Task和TaskScheduler创建自己的线程池的示例。

http://msdn.microsoft.com/en-us/library/dd997413(VS.100).aspx

只有一个线程池。

虽然Windows API允许进程中有多个线程池 ,但.NET不直接公开它,但是:

每个.NET AppDomain只有一个.NET ThreadPool ,绝对没办法改变它。

因此,对于不同的应用程序域,可以在同一进程中使用不同的.NET ThreadPools。

(注意:.NET中使用的Hill Climb算法的启发式算法也是基于per-.NET ThreadPool确定的。这一点,以及能够指定每种类型的最大工作数量,是’全局每个appdomain’ThreadPool,具有不同的工作负载。)

一种方法是使用BlockingCollection。 这是我为它构建的类:

更新于2018-04-23:

 public class WorkerPool : IDisposable { BlockingCollection queue = new BlockingCollection(); List taskList; private CancellationTokenSource cancellationToken; int maxWorkers; private bool wasShutDown; int waitingUnits; public WorkerPool(CancellationTokenSource cancellationToken, int maxWorkers) { this.cancellationToken = cancellationToken; this.maxWorkers = maxWorkers; this.taskList = new List(); } public void enqueue(T value) { queue.Add(value); waitingUnits++; } //call to signal that there are no more item public void CompleteAdding() { queue.CompleteAdding(); } //create workers and put then running public void startWorkers(Action worker) { for (int i = 0; i < maxWorkers; i++) { taskList.Add(new Task(() => { string myname = "worker " + Guid.NewGuid().ToString(); try { while (!cancellationToken.IsCancellationRequested) { var value = queue.Take(); waitingUnits--; worker(value); } } catch (Exception ex) when (ex is InvalidOperationException) //throw when collection is closed with CompleteAdding method. No pretty way to do this. { //do nothing } })); } foreach (var task in taskList) { task.Start(); } } //wait for all workers to be finish their jobs public void await() { while (waitingUnits >0 || !queue.IsAddingCompleted) Thread.Sleep(100); shutdown(); } private void shutdown() { wasShutDown = true; Task.WaitAll(taskList.ToArray()); } //case something bad happen dismiss all pending work public void Dispose() { if (!wasShutDown) { queue.CompleteAdding(); shutdown(); } } } 

要看它工作,建立这个unit testing:

 [TestMethod] public void workerPoolTest() { WorkerPool workerPool = new WorkerPool(new CancellationTokenSource(), 5); workerPool.startWorkers(value => { log.Debug(value); }); for (int i = 0; i < 100; i++) { workerPool.enqueue(i); } workerPool.CompleteAdding(); workerPool.await(); } 

现在,只需创建新的WorkPool对象,就可以拥有尽可能多的民意调查。

请注意,代码未经过完全测试。