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

发布于 2024-08-20 14:28:20 字数 191 浏览 4 评论 0 原文

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

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

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

If I use the ThreadPool in a nested way, my application hangs:

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

How to get a second and independent ThreadPool to achieve nesting?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

暖风昔人 2024-08-27 14:28:20

只有一个 ThreadPool - 您不能(或应该)在应用程序中创建多个实例。

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

但是,我怀疑您挂起是由于死锁,而不是由于线程池的使用。我会调查一下你的困境在哪里。如果您安装了 VS 2010 beta 的副本,VS2010 并发可视化工具对此非常有用。

There is only one single ThreadPool - it's not something you can (or should) make more than one instance of in an application.

I don't recommend doing this, but if you really wanted to, you could use multiple instances of your own ThreadPool implementation, such as SmartThreadPool. This would, technically, allow separate "thread pools".

However, I suspect you're hanging due to a deadlock, not due to the ThreadPool usage. I would investigate where you're getting the hangs. The VS2010 concurrency visualizer is very nice for this, if you have a copy of the VS 2010 beta installed.

ˉ厌 2024-08-27 14:28:20

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

默认情况下,ThreadPool 有 25 *(CPU 数量)个工作线程 (IIRC)。

您可能想要重新调整项目的排队方式。如果您将它们排队,然后完成并退出线程,那就没问题,但是让工作项挂在等待其他进程上通常是一个糟糕的设计;如果这就是您正在做的事情,您可能需要使用真正的线程或完全不同的设计。使用真正的线程可能也是一个同样糟糕的主意,因为所有这一切(根据我对你的使用情况的推测)只会创建大量线程,这对你的性能没有任何好处。

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

Your application is probably hanging because you are filling it up to the point where all of the active threads are waiting on queued threads. (I assume the original thread is waiting for the work item(s) it queues to complete.)

The ThreadPool has by default 25 * (number of CPUs) worker threads (IIRC).

You probably want to rework the way you're queuing items. If you're queuing them up and then finishing and exiting the thread, you're fine, but having work items hanging around waiting on other processes is generally a bad design; if that's what you're doing you probably need to use real threads or a completely different design. Using real threads is probably an equally bad idea because all that will do (based on what I can surmise of your usage) you'll just create a large number of threads, which will do nothing good for your performance.

A better design might be to have some kind of queue or stack that a few (2-4 depending on number of CPUs) worker threads add items to and pop items off to work. If an item needs to queue a new item it just adds it to the stack (and adds itself back to the stack with some kind of dependency tracking if it needs to wait for the other item).

一瞬间的火花 2024-08-27 14:28:20

您使用了错误的工具。

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

从 Task 类开始,它取代了 ThreadPool.QueueUserWorkItem。

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

编辑

使用任务和任务调度程序创建自己的线程池的示例。

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

You are using the wrong tools.

In .NET 4.0 they introduced the Task Parallel Library. This allows you to do things like use multiple thead pools as well as have parent-child relationships between work items.

Start with the Task class, which replaces ThreadPool.QueueUserWorkItem.

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

EDIT

Example of creating your own thread pool using Task and TaskScheduler.

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

楠木可依 2024-08-27 14:28:20

虽然 Windows API 允许多个进程中的线程池,.NET 不会直接公开它。在 .NET Framework 中......

每个 .NET AppDomain 仅有一个 .NET 线程池,而且绝对没有办法改变这一点。

因此,对于不同的应用程序域……同一进程中可能有不同的 .NET 线程池。

(注意:.NET 中使用的 Hill Climb 算法的启发式也是基于每个 .NET ThreadPool 确定的。这无法指定每种类型的最大工作线程数,具有不同工作负载的“每个应用程序域全局”线程池的缺点。)

While the Windows API allows for multiple Thread Pools in a process, .NET does not directly expose this. In the .NET Framework..

There is Exactly One .NET ThreadPool per .NET AppDomain, and absolutely no way to change this.

So with different application domains.. it is possible to have different .NET ThreadPools within the same process.

(NOTE: The heuristics for the Hill Climb algorithm used in .NET is also determined on a per-.NET ThreadPool basis. This, along without being able to specify a maximum number of workers per type, is a downside of a 'global per appdomain' ThreadPool with varied workloads.)

楠木可依 2024-08-27 14:28:20

有且只有一个线程池。

There is one and only one threadpool.

李白 2024-08-27 14:28:20

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

更新于 2018-04-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();
        }
    }
}

要查看它的工作原理,请构建此单元测试:

[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();
}

现在您可以进行任意数量的民意调查,只需创建新的 WorkPool 对象。

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

One way is using BlockingCollection.
This is the class i build for it:

Updated at 2018-04-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();
        }
    }
}

To see it working build this unit test:

[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();
}

Now you can have as many polls has you like, just by creating new WorkPool objects.

Note that the code is not fully tested.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文