.NET Custom Threadpool с отдельными экземплярами - PullRequest
11 голосов
/ 23 июня 2009

Какой самый рекомендуемый пользовательский пул потоков .NET может иметь отдельные экземпляры, т.е. более одного пула потоков на приложение? Мне нужен неограниченный размер очереди (создание сканера), и мне нужно параллельно запускать отдельный пул потоков для каждого просматриваемого сайта.

Редактировать: Мне нужно как можно быстрее добывать эти сайты для получения информации, поскольку использование отдельного пула потоков для каждого сайта позволило бы мне контролировать количество потоков, работающих на каждом сайте, в любой момент времени. (не более 2-3)

Спасибо Roey

Ответы [ 6 ]

7 голосов
/ 23 июня 2009

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

3 голосов
/ 23 июня 2009

Ami bar написал отличный пул Smart-потоков, который может быть создан.

посмотрите здесь

1 голос
/ 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();
        }
    }
}

Тогда используйте вот так:

WorkerPool<int> workerPool = new WorkerPool<int>(new CancellationTokenSource(), 5);

workerPool.startWorkers(value =>
{
    log.Debug(value);
});
//enqueue all the work
for (int i = 0; i < 100; i++)
{
    workerPool.enqueue(i);
}
//Signal no more work
workerPool.CompleteAdding();

//wait all pending work to finish
workerPool.await();

Вы можете иметь столько опросов, сколько хотите, просто создавая новые объекты WorkPool.

1 голос
/ 23 июня 2009

Спросите Джона Скита: http://www.yoda.arachsys.com/csharp/miscutil/

Параллельные расширения для .Net (TPL) на самом деле должны работать намного лучше, если вам нужно большое количество параллельно выполняемых задач.

0 голосов
/ 19 декабря 2018

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

Вы можете разбить свой код на один или несколько блоков, затем связать их с потоками данных, а затем дать возможность механизму потоков данных распределять потоки в соответствии с доступностью процессора и памяти

Я предлагаю разбить на 3 блока: один для подготовки запроса к странице сайта, один для доступа к странице сайта и последний для анализа данных. Таким образом, медленный блок (get) может иметь больше потоков, выделенных для компенсации.

Вот как будет выглядеть настройка Dataflow:

var linkOptions = new DataflowLinkOptions { PropagateCompletion = true };

prepareBlock.LinkTo(get, linkOptions);
getBlock.LinkTo(analiseBlock, linkOptions);

Данные будут передаваться с prepareBlock до getBlock, а затем до analiseBlock. Интерфейсы между блоками могут быть любого класса, просто должны быть одинаковыми. См. Полный пример на конвейере потока данных

Использование потока данных будет примерно таким:

 while ...{
    ...
    prepareBlock.Post(...); //to send data to the pipeline
 }
 prepareBlock.Complete(); //when done
 analiseBlock.Completion.Wait(cancellationTokenSource.Token); //to wait for all queues to empty or cancel 
0 голосов
/ 14 февраля 2013

Эта бесплатная библиотека Nuget здесь: CodeFluentRuntimeClient имеет класс CustomThreadPool, который вы можете использовать повторно. Это очень настраивается, вы можете изменить приоритет потоков пула, номер, состояние квартиры COM, даже имя (для отладки), а также культуру.

...