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();
}
现在,只要创建新的工作池对象,您就可以进行任意数量的轮询。


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

为什么要嵌套线程池?这不应该导致程序挂起。你可能