Обработка списка элементов с использованием нескольких ограниченных потоков - PullRequest
2 голосов
/ 03 марта 2011

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

foreach item in list
    while thread_count >= thread_max
        sleep
    loop
    start_thread item
    thread_count++
next

function start_thread(item)
    do_something_to item
    thread_count--
end function

Ответы [ 2 ]

6 голосов
/ 03 марта 2011

Я бы использовал PLINQ для этого и указал бы максимальную степень параллелизма следующим образом:

Я на самом деле меняю свой ответ на этот вопрос, потому что понял, что вы просто хотите обработатьнеобработанный список напрямую, и вы не делаете никакой другой фильтрации или сопоставления (где / выберите).В этом конкретном случае было бы лучше использовать Parallel :: ForEach и указать MaxDegreeOfParallelism через ParallelOptions, например, так:

 int myMaxDegreeOfParallelism = 4; // read this from config maybe

 Parallel.ForEach(
    list,
    new ParallelOptions
    {
        MaxDegreeOfParallelism = myMaxDegreeOfParallelism
    }
    item =>
    {
        // ... your work here ...
    });

Теперь, имейте в виду, что когда вы указываете максимальное значение, подобное этому, вы предотвращаете использование PLINQ.возможность использовать любые другие ресурсы, даже если они доступны.Таким образом, если бы он работал на 8-ядерном компьютере, он никогда не использовал бы более 4-х ядер.И наоборот, если вы указали 4, это не означает, что 4 гарантированно будут выполняться одновременно в любой момент времени.Все зависит от нескольких эвристик, которые TPL использует, чтобы быть оптимальными.

1 голос
/ 03 марта 2011

Это имеет смысл, но я надеюсь, что вы знаете, что это не обычный способ сделать это, если у вас нет особых причин производительности или вы застряли на .NET 3.5. Обычно вы используете Parallel.ForEach над элементами в списке и полагаетесь на разделитель для разделения работы на соответствующие куски.

Даже если у вас не было TPL, было бы более идиоматично разделять всю работу и передавать каждому потоку большую часть работы сразу, а не раздавать ее по частям в момент завершения потока. Единственная причина сделать это по-своему, если вы ожидали, что время, затрачиваемое данным рабочим элементом, будет более или менее непредсказуемым, поэтому вы не сможете заранее разделить работу.

(Кроме того, вы можете просто сохранить ссылки на потоки и проверить, сколько из них все еще работает и сколько завершено. Это могло бы покончить с переменной.)

...