Распараллеливание ввода-вывода связаны (сети) цикл foreach


У меня есть несколько различных способов загрузки целых каталогов в Amazon S3 в моем приложении в зависимости от того, какие параметры выбраны. В настоящее время один из вариантов будет выполнять загрузку нескольких каталогов параллельно. Я не уверен, что это хорошая идея, поскольку в некоторых случаях она ускорила загрузку, а в других-замедлила ее. Скорость увеличивается, когда есть куча небольших каталогов, но она замедляется, если в пакете есть большие каталоги. Я использую ... параллельный цикл ForEach, рассмотренный ниже и использующий метод AWS API TransferUtility.UploadDirectoryAsync() как таковой:

Parallel.ForEach(dirs,myParallelOptions, 
                   async dir => { await MyUploadMethodAsync(dir) };

, где метод TransferUtility.UploadDirectoryAsync() находится в пределах MyUploadMethodAsync(). Все методы загрузки TransferUtility выполняют параллельную загрузку частей одного файла (если размер достаточно велик для этого), поэтому выполнение параллельной загрузки каталога также может быть излишним. Очевидно, что мы все еще ограничены количеством доступной полосы пропускания, поэтому это может быть пустой тратой времени, и я просто должен использовать обычный цикл foreach с UploadDirectoryAsync() метод. Может ли кто-нибудь дать некоторое представление о том, является ли это плохим случаем для распараллеливания?

1 4

1 ответ:

Вы действительно проверяли это? То, как вы его используете, Parallel.ForEach может вернуться задолго до завершения любого из MyUploadMethodAsync, потому что async лямбда:

Parallel.ForEach(dirs,myParallelOptions, 
    async dir => { await MyUploadMethodAsync(dir) };

Parallel.ForEach подходит для задач, связанных с процессором. Для задач, связанных с IO, вы, вероятно, ищете что-то вроде этого:

var tasks = dirs.Select(dir => MyUploadMethodAsync(dir));
await Task.WhenAll(tasks);
// or Task.WaitAll(tasks) if you need a blocking wait