C # - передать данные обратно из потока ThreadPool в основной поток - PullRequest
1 голос
/ 19 ноября 2010

Текущая реализация: ожидает сбора значений parallelCount, использует ThreadPool для обработки значений, ожидает завершения всех потоков, повторного сбора другого набора значений и т. Д. *

Код:

private static int parallelCount = 5;
private int taskIndex;
private object[] paramObjects;

// Each ThreadPool thread should access only one item of the array, 
// release object when done, to be used by another thread
private object[] reusableObjects = new object[parallelCount];     

private void MultiThreadedGenerate(object paramObject)
{
    paramObjects[taskIndex] = paramObject;
    taskIndex++;

    if (taskIndex == parallelCount)
    { 
        MultiThreadedGenerate();

        // Reset
        taskIndex = 0;
    }
}

/*
 * Called when 'paramObjects' array gets filled
 */
private void MultiThreadedGenerate()
{
    int remainingToGenerate = paramObjects.Count;

    resetEvent.Reset();

    for (int i = 0; i < paramObjects.Count; i++)
    {
        ThreadPool.QueueUserWorkItem(delegate(object obj)
        {
            try
            {
                int currentIndex = (int) obj;       

                Generate(currentIndex, paramObjects[currentIndex], reusableObjects[currentIndex]);
            }
            finally
            {
                if (Interlocked.Decrement(ref remainingToGenerate) == 0)
                {
                    resetEvent.Set();
                }
            }
        }, i);
    }

    resetEvent.WaitOne();    
}

Я видел существенные улучшения производительности с этим подходом, однако есть ряд вопросов, которые необходимо учитывать:

[1] Сбор значений в paramObjects и синхронизация с использованием resetEvent можно избежать, поскольку нет никакой зависимости между потоками (или текущим набором значений со следующим набором значений).Я делаю это только для управления доступом к reusableObjects (когда обработка набора paramObjects завершена, я знаю, что все объекты в reusableObjects свободны, поэтому taskIndex сбрасывается, и каждая новая задача из следующего набора значенийбудет иметь уникальный 'reusableObj' для работы).

[2] Нет реальной связи между размером reusableObjects и количеством потоков, используемых ThreadPool.Я мог бы инициализировать reusableObjects, чтобы иметь 10 объектов, и сказать, что из-за некоторых ограничений ThreadPool может запустить только 3 потока для моего MultiThreadedGenerate() метода, тогда я трачу впустую память.

Таким образом, избавляясь от paramObjects, как можно усовершенствовать приведенный выше код таким образом, чтобы, как только один поток завершил свою работу, этот поток возвращал использованный им taskIndex (или reusableObj) и больше не нужен, чтобы он стал доступен дляследующее значениеКроме того, код должен создать reUsableObject и добавить его в некоторую коллекцию только тогда, когда есть спрос на него.Является ли использование очереди здесь хорошей идеей?

Спасибо.

1 Ответ

5 голосов
/ 19 ноября 2010

На самом деле больше нет причин для ручного создания потоков и управления задачами.Вы можете реструктурировать это в более слабосвязанную модель, используя Task Parallel Library (и, возможно, System.Collections.Concurrent для сопоставления результатов).

Производительность может быть улучшена, если вам не нужно ждать полного завершения работы, прежде чем передавать каждый Task для обработки.

TPL появился в .Net 4.0, но был перенесен в .Net 3.5 .Скачать здесь .

...