Как получить второй System.Thread.ThreadPool? - PullRequest
4 голосов
/ 05 февраля 2010

Если я использую ThreadPool вложенным способом, мое приложение зависает:

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

Как получить второй и независимый ThreadPool для достижения вложенности?

Ответы [ 6 ]

6 голосов
/ 05 февраля 2010

Существует только один единственный ThreadPool - это не то, что вы можете (или должны) создавать более одного экземпляра в приложении.

Я не рекомендую делать это, но если вы действительно хотите, вы можете использовать несколько экземпляров своей собственной реализации ThreadPool, например SmartThreadPool . Технически это позволило бы разделить «пулы потоков».

Однако я подозреваю, что вы зависаете из-за тупика , а не из-за использования ThreadPool. Я бы расследовал, где вы получаете зависания. Параллельный визуализатор VS2010 очень хорош для этого, если у вас установлена ​​копия бета-версии VS 2010.

4 голосов
/ 05 февраля 2010

Ваше приложение, вероятно, зависает, потому что вы заполняете его до того момента, когда все активные потоки ожидают в очередях. (Я предполагаю, что исходный поток ожидает выполнения рабочего (ых) элемента (ов), который он ставит в очередь.)

ThreadPool по умолчанию имеет 25 * (количество процессоров) рабочих потоков (IIRC).

Вы, вероятно, хотите переделать способ, которым вы ставите в очередь предметы. Если вы ставите их в очередь, а затем заканчиваете и выходите из потока, у вас все хорошо, но работа с элементами, ожидающими другие процессы, как правило, плохой дизайн; если это то, что вы делаете, вам, вероятно, нужно использовать реальные темы или совершенно другой дизайн. Использование реальных потоков, вероятно, не менее плохая идея, потому что все, что будет делать (основываясь на том, что я могу догадаться о вашем использовании), вы просто создадите большое количество потоков, которые не принесут ничего хорошего вашей производительности.

Лучшим дизайном может быть наличие какой-либо очереди или стека, в которые несколько (2-4 в зависимости от количества процессоров) рабочих потоков добавляют элементы и извлекают элементы для работы. Если элементу нужно поставить в очередь новый элемент, он просто добавляет его в стек (и добавляет себя обратно в стек с некоторым отслеживанием зависимостей, если ему нужно ждать другого элемента).

2 голосов
/ 05 февраля 2010

Вы используете неправильные инструменты.

В .NET 4.0 они представили параллельную библиотеку задач. Это позволяет вам использовать такие вещи, как использование нескольких пулов thead, а также иметь отношения родитель-потомок между рабочими элементами.

Начните с класса Task, который заменяет ThreadPool.QueueUserWorkItem.

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

EDIT

Пример создания собственного пула потоков с помощью Task и TaskScheduler.

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

0 голосов
/ 16 апреля 2018

Одним из способов является использование 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.

Обратите внимание, что код не полностью протестирован.

0 голосов
/ 10 октября 2017

В то время как Windows API допускает использование нескольких пулов потоков в процессе , .NET не напрямую предоставляет это, однако:

Существует только один .NET ThreadPool на .NET AppDomain , и абсолютно невозможно изменить это.

То есть, с разными доменами приложений ... в одном и том же процессе могут быть разные .NET ThreadPools.

(ПРИМЕЧАНИЕ. Эвристика для алгоритма Hill Climb, используемого в .NET, также определяется для каждого .NET ThreadPool. Это, наряду с возможностью указывать максимальное количество работников для каждого типа, является недостатком ThreadPool 'global per appdomain' с различными рабочими нагрузками.)

0 голосов
/ 05 февраля 2010

Существует один и только один пул потоков.

...