ActionBlock‹T› против Task.WhenAll

Я хотел бы знать, каков рекомендуемый способ параллельного выполнения нескольких асинхронных методов?

в System.Threading.Tasks.Dataflow мы можем указать максимальную степень параллелизма, но unbounded, вероятно, используется по умолчанию и для Task.WhenAll?

это :

var tasks = new List<Task>();
foreach(var item in items)
{
    tasks.Add(myAsyncMethod(item));
}
await Task.WhenAll(tasks.ToArray());

или это :

var action = new ActionBlock<string>(myAsyncMethod, new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
            BoundedCapacity = DataflowBlockOptions.Unbounded,
            MaxMessagesPerTask = DataflowBlockOptions.Unbounded
        });
foreach (var item in items) { }
{
     action.Post(item);
}
action.Complete();

await action.Completion;

person fred_    schedule 16.05.2016    source источник
comment
Параллельный и асинхронный не так хорошо сочетаются, и методы асинхронные (я не могу их изменить)   -  person fred_    schedule 16.05.2016
comment
Показанный вами код Task.WhenAll не имеет ничего общего с параллельным выполнением задач - любые решения об использовании, например. потоки пула потоков, параллелизм и т. д. происходят внутри myAsyncMethod, который (предположительно) возвращает горячие Tasks.   -  person Damien_The_Unbeliever    schedule 16.05.2016
comment
Просто заметка. BoundedCapacity = DataflowBlockOptions.Unbounded по умолчанию. Включив его явно в параметры, вы открываете возможность того, что вы или кто-то другой в будущем решит настроить его на лучшее значение. И тогда ваша программа начнет вести себя странно, и вы потратите полтора дня на то, чтобы понять, почему.   -  person Theodor Zoulias    schedule 30.10.2019
comment
Метод Post отбрасывает элементы на пол, когда принимающий блок отказывается их принимать, потому что его буфер переполнен. Чтобы избежать этой неприятной ситуации, лучше проявить инициативу и использовать await action.SendAsync(item) или action.SendAsync(item).Wait(), если вы не находитесь внутри асинхронного метода. Накладные расходы на SendAsync незначительно.   -  person Theodor Zoulias    schedule 30.10.2019


Ответы (2)


Я хотел бы знать, каков рекомендуемый способ параллельного выполнения нескольких асинхронных методов?

Примечание: на самом деле не параллельно, а параллельно.

в System.Threading.Tasks.Dataflow мы можем указать максимальную степень параллелизма, но unbounded, вероятно, используется по умолчанию и для Task.WhenAll?

Как кто-то прокомментировал, Task.WhenAll только присоединяется к существующим задачам; к тому времени, когда ваш код дойдет до Task.WhenAll, все решения параллелизма уже приняты.

Вы можете регулировать простой асинхронный код, используя что-то вроде SemaphoreSlim.

Решение о том, использовать ли асинхронный параллелизм напрямую или поток данных TPL, зависит от окружающего кода. Если эта параллельная операция вызывается только один раз асинхронно, то асинхронный параллелизм — лучший выбор; но если эта параллельная операция является частью «конвейера» для ваших данных, то TPL Dataflow может подойти лучше.

person Stephen Cleary    schedule 16.05.2016

Оба метода приемлемы, и выбор должен определяться вашими требованиями, поскольку вы можете видеть, что Dataflow предоставляет вам множество возможностей настройки, которые в противном случае вам пришлось бы реализовывать вручную при непосредственном использовании Tasks.

Обратите внимание, что в обеих ситуациях пул задач будет отвечать за постановку в очередь и выполнение задач, поэтому поведение должно остаться прежним.

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

person Slugart    schedule 16.05.2016
comment
хорошо, если это просто для параллелизма без привязки, так как нет реальных преимуществ? - person fred_; 16.05.2016
comment
Если вам не нужна цепочка или компонуемость, это может быть излишним, да - person Slugart; 16.05.2016