Контроль порядка выполнения параллельных задач. - PullRequest
1 голос
/ 15 апреля 2020

У меня есть список имен таблиц (ученик, экзамен, школа).

Я использую Parallel.ForEach l oop, чтобы перебрать имена таблиц и выполнить обработку для каждой таблицы, с MaxDegreeOfParallelism = 8.

Моя проблема в том, что мой Parallel.ForEach не всегда занимается кражей работы. Например, когда две таблицы оставлены для обработки, они могут обрабатываться одна за другой, а не параллельно. Я пытаюсь улучшить производительность и увеличить пропускную способность.

Я пытался сделать это, создав пользовательский TaskScheduler, однако для моей реализации мне нужен отсортированный список задач, в котором сначала заказываются самые простые задачи, поэтому что они не задерживаются более продолжительными столами. Похоже, я не могу сделать это путем сортировки списка, переданного в Parallel.ForEach (List< string >), потому что задачи ставятся в очередь TaskScheduler вне очереди. Поэтому мне нужен способ сортировки списка задач внутри моего CustomTaskScheduler, который основан на https://psycodedeveloper.wordpress.com/2013/06/28/a-custom-taskscheduler-in-c/

Как я могу контролировать порядок, в котором задачи передаются Parallel.ForEach к TaskScheduler в очереди?

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

Метод Parallel.ForEach использует две разные стратегии разделения в зависимости от типа источника. Если источником является массив или List, он статически разбивается (аванс). Если источником является честное слово ¹ IEnumerable, оно динамически разбивается (на go). Динамическое разбиение c имеет желаемое поведение кражи труда, но имеет больше накладных расходов. В вашем случае издержки не важны, потому что степень детализации вашей рабочей нагрузки очень мала.

Чтобы обеспечить динамическое разбиение c, самый простой способ - обернуть ваш источник с помощью Partitioner.Create метод:

string[] tableNames;
Parallel.ForEach(Partitioner.Create(tableNames), tableName =>
{
    // Process table
});

¹ (Выражение заимствовано из комментария в исходном коде )

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

Я бы порекомендовал поискать разделителей . Управление потоками в Parallel l oop имеет некоторые накладные расходы, поэтому есть некоторые встроенные логи c, чтобы попытаться сохранить эти издержки небольшими, при этом все равно равномерно распределяя работу между всеми ядрами. Это можно сделать, разделив список на куски и отрегулировав размер фрагмента так, чтобы он достиг некоторой привлекательности.

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

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

Кроме того, если вы тратите много времени на оптимизацию распараллеливания, уверены ли вы, что остальная часть кода оптимизирована?

...