C# 如何获得第二个System.Thread.ThreadPool?
如果以嵌套方式使用线程池,我的应用程序将挂起:C# 如何获得第二个System.Thread.ThreadPool?,c#,.net,multithreading,threadpool,nested,C#,.net,Multithreading,Threadpool,Nested,如果以嵌套方式使用线程池,我的应用程序将挂起: ThreadPool.QueueUserWorkItem((state) => ThreadPool.QueueUserWorkItem(Action)); 如何获得第二个独立的线程池来实现嵌套?只有一个线程池。您的应用程序可能挂起,因为您正在填充它,直到所有活动线程都在排队等待线程。(我假设原始线程正在等待队列中的工作项完成。) 默认情况下,线程池有25*(CPU数量)个工作线程(IIRC) 你可能想改变排队的方式。如果您将
ThreadPool.QueueUserWorkItem((state) =>
ThreadPool.QueueUserWorkItem(Action));
如何获得第二个独立的线程池来实现嵌套?只有一个线程池。您的应用程序可能挂起,因为您正在填充它,直到所有活动线程都在排队等待线程。(我假设原始线程正在等待队列中的工作项完成。) 默认情况下,线程池有25*(CPU数量)个工作线程(IIRC) 你可能想改变排队的方式。如果您将它们排队,然后完成并退出线程,则可以,但让工作项挂起等待其他进程通常是一种糟糕的设计;如果这就是你正在做的,你可能需要使用真正的线程或完全不同的设计。使用真正的线程可能是一个同样糟糕的主意,因为这样做(根据我对您的使用情况的推测)只会创建大量线程,这对您的性能没有任何好处
更好的设计可能是使用某种队列或堆栈,几个(2-4个,取决于CPU的数量)工作线程将项目添加到其中,然后将项目弹出以工作。如果一个项目需要对一个新项目进行排队,它只会将其添加到堆栈中(如果它需要等待另一个项目,则会使用某种依赖项跟踪将其自身添加回堆栈)。只有一个线程池-您不能(或不应该)在应用程序中创建多个线程池实例 我不建议这样做,但如果您真的想这样做,您可以使用自己的线程池实现的多个实例,例如。从技术上讲,这将允许单独的“线程池”
但是,我怀疑您被挂起是由于线程池的使用,而不是由于线程池的使用。我会调查你在哪里被绞死的。如果您安装了VS2010测试版的副本,VS2010并发可视化工具在这方面非常好。您使用了错误的工具 在.NET4.0中,他们引入了任务并行库。这允许您执行诸如使用多个thead池以及在工作项之间建立父子关系之类的操作 从替换ThreadPool.QueueUserWorkItem的Task类开始 编辑 使用Task和TaskScheduler创建自己的线程池的示例 而.NET不会直接公开此内容。在.NET框架中 每个.NET AppDomain正好有一个.NET线程池,绝对没有办法改变这一点 因此,对于不同的应用程序域。。在同一进程中可能有不同的.NET线程池
(注意:.NET中使用的爬山算法的试探法也是基于每.NET线程池确定的。这与无法指定每种类型的最大工作线程数一起,是具有不同工作负载的“每appdomain全局”线程池的缺点。)一种方法是使用BlockingCollection。 这是我为它构建的类: 于2018年4月23日更新:
public class WorkerPool<T> : IDisposable
{
BlockingCollection<T> queue = new BlockingCollection<T>();
List<Task> 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<Task>();
}
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<T> 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();
}
}
}
public类WorkerPool:IDisposable
{
BlockingCollection队列=新建BlockingCollection();
列表任务列表;
私有CancellationTokenSource cancellationToken;
int maxWorkers;
私营部门关闭;
国际等待单位;
公共WorkerPool(CancellationTokenSource cancellationToken,int-maxWorkers)
{
this.cancellationToken=cancellationToken;
this.maxWorkers=maxWorkers;
this.taskList=新列表();
}
公共无效排队(T值)
{
添加(值);
waitingUnits++;
}
//呼叫以发出没有其他项目的信号
公共无效完成添加()
{
queue.CompleteAdding();
}
//创建工人,然后运行
公众无效startWorkers(行动工作者)
{
对于(int i=0;i
{
字符串myname=“worker”+Guid.NewGuid().ToString();
尝试
{
而(!cancellationToken.IsCancellationRequested)
{
var value=queue.Take();
等待单位--;
工人(价值);
}
}
catch(Exception ex)when(ex是invalidooperation Exception)//在使用CompleteAdding方法关闭集合时抛出。没有很好的方法可以做到这一点。
{
//无所事事
}
}));
}
foreach(任务列表中的var任务)
{
task.Start();
}
}
//等待所有工人完成他们的工作
公共空间等待()
{
while(waitingUnits>0 | |!queue.IsAddingCompleted)
睡眠(100);
关机();
}
私有无效关闭()
{
washutdown=true;
Task.WaitAll(taskList.ToArray());
}
//万一发生了不好的事情,就解雇所有待处理的工作
公共空间处置()
{
如果(!wasShutDown)
{
queue.CompleteAdding();
关机();
}
}
}
要使其工作,请构建此单元测试:
[TestMethod]
public void workerPoolTest()
{
WorkerPool<int> workerPool = new WorkerPool<int>(new CancellationTokenSource(), 5);
workerPool.startWorkers(value =>
{
log.Debug(value);
});
for (int i = 0; i < 100; i++)
{
workerPool.enqueue(i);
}
workerPool.CompleteAdding();
workerPool.await();
}
[TestMethod]
public void workerPoolTest()
{
WorkerPool WorkerPool=newworkerpool(new CancellationTokenSource(),5);
workerPool.startWorkers(值=>
{
log.Debug(值);
});
对于(int i=0;i<100;i++)
{
workerPool.enqueue(一);
}
workerPool.CompleteAdding();
workerPool.await();
}
现在,只要创建新的工作池对象,您就可以进行任意数量的轮询。
请注意,代码没有经过完全测试。为什么要嵌套线程池?这不应该导致程序挂起。你可能