asyn c и шаблон ожидания не очень подходят для вашего первого метода. Он хорошо подходит для ограниченных рабочих нагрузок ввода-вывода для достижения масштабируемости или для каркасов, которые имеют пользовательский интерфейс для отзывчивости. Он менее подходит для необработанных рабочих нагрузок процессора .
Однако вы все равно можете получить выгоду от параллельной обработки , потому что ваш первый метод дорогой и поточно-безопасный .
В следующем примере я использовал Parallel LINQ (PLINQ) для быстрого выражения результатов, не беспокоясь о массиве pre-size / одновременной коллекции / блокировка , хотя вы можете использовать другие функции TPL , например Parallel.For/ForEach
// Potentially break up the workloads in parallel
// return the number and result in a ValueTuple
var results = numbers.AsParallel()
.Select(x => (number: x, result: ComputeResult(x)))
.ToList();
// iterate through the number and results and execute them serially
foreach (var (number, result) in results)
AddResultToDb(number, result);
Примечание : предположение, что порядок здесь не важен
Дополнительный
Ваш метод AddResultToDb
выглядит так, как будто он просто вставляется результаты в базу данных , которая IO Bound и достойна async
, более того, вероятно, может взять все результаты сразу и вставить их в bulk / batch экономия поездки туда и обратно
Из комментариев кредит @ TheodorZoulias
До сохранить Для заказа вы можете использовать метод AsOrdered за счет некоторого снижения производительности. Возможное улучшение производительности - удалить ToList()
, чтобы результаты добавлялись в БД одновременно с вычислениями.
Чтобы сделать результаты доступными как можно быстрее, вероятно, хорошей идеей будет отключение частичного буферизация, которая происходит по умолчанию , путем цепочки метода .WithMergeOptions(ParallelMergeOptions.NotBuffered)
в запросе
var results = numbers.AsParallel()
.Select(x => (number: x, result: ComputeResult(x)))
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
.AsOrdered();
Пример
Дополнительные ресурсы
ParallelEnumerable.AsOrdered Method
Включает обработку источника данных, как если бы он был упорядочен, переопределяя значение по умолчанию для неупорядоченных , AsOrdered
может вызываться только для неуниверсальных последовательностей
ParallelEnumerable.WithMergeOptions
Устанавливает параметры слияния для этого запроса, которые определяют, как запрос будет буферизовать вывод.
ParallelMergeOptions Enum
NotBuffered Использовать слияние без выходных буферов. Как только будут вычислены элементы результата, сделайте этот элемент доступным для потребителя запроса.