2016-08-23 5 views
2

У меня есть несколько тысяч независимых задач, которые нужно запустить. Каждый из них может выполнять вызовы базы данных, поэтому они, по возможности, уже используют async. Тем не менее, если бы я хотел, чтобы все они работали параллельно, что это лучший способ сделать это?Лучший способ запуска нескольких асинхронных задач параллельно?

Я получил это в настоящее время:

Parallel.For(0, items.Count, async _ => await PerformTask()); 

Я также рассматривал возможность использования:

List<Task> tasks = new List<Task>(); 
for(var i = 0; i < items.Count; ++i) tasks.Add(PerformTask()); 
await Task.WhenAll(tasks); // or possibly Task.WaitAll(tasks.ToArray()) 

Есть объективно лучший способ сделать это?

Редактировать: Это отличается от отмеченного дублирующегося вопроса, так как я не прошу разницы. Я спрашиваю, какой путь правильный для моего варианта использования.

+1

Возможный дубликат [Parallel.ForEach vs Task.Run and Task.WhenAll] (http://stackoverflow.com/questions/19102966/parallel-foreach-vs-task-run-and-task-whenall) – Liam

+0

для последняя часть, 'Task.WhenAll', вероятно, предпочтительнее, так как она возвращает задачу. 'Task.WaitAll' возвращает void и блокирует до полного завершения. – Jonesopolis

+0

@ Liam, а не дубликат, см. Править. Ответы на связанный ответ фактически не указывают, что следует использовать при определенных обстоятельствах. И не похоже, что есть ответ «только так». – Charles

ответ

1

Parallel не является вариантом, поскольку у вас есть асинхронные действия.

варианты:

  • Start все из задач одновременно, а затем использовать await Task.WhenAll для них все, чтобы закончить. Вы можете использовать SemaphoreSlim, если вам нужно активировать количество активных задач.
  • Используйте команду ActionBlock<T> (из потока данных TPL) для индивидуальной работы в очереди. Вы можете использовать ExecutionDataflowBlockOptions.MaxDegreeOfParallelism, если вы хотите обрабатывать более одного одновременно.

ActionBlock<T> подход был бы лучше, если вы не знаете обо всех задач, в то время они начали (то есть, если больше может прибыть в то время как вы обрабатываете), или если другие близлежащие части вашего код будет вписываться в «конвейерный» вид дизайна.

Task.WhenAll приятно, потому что для этого не требуется отдельная библиотека с собственной философией дизайна и кривой обучения.

Либо Task.WhenAll, либо ActionBlock<T> будет хорошо работать для вашего использования.

+0

Gotcha, в моем случае я знаю каждую задачу, которая будет запущена, поэтому 'ActionBlock ' теряет свой край, я полагаю. В целом, время обработки чрезвычайно мало для каждой отдельной задачи, вплоть до вызова БД. Мне комфортно с распределением распределений запросов для меня, поэтому я буду придерживаться 'Task.WhenAll'. Благодаря! – Charles

Смежные вопросы