private static async Task RunLoopAsync <T>( EnumeratorInfo <T> enumerator, T item, int index, ConcurrentQueue <Exception> exceptions, Func <T, int, CancellationToken, Task> func, CancellationToken cancelToken) { do { if (exceptions.Count > 0) { return; } try { await func(item, index, cancelToken).ConfigureAwait(false); } catch (Exception ex) { exceptions.Enqueue(ex); return; } }while (enumerator.TryGetNext(out item, out index)); }
public static async Task WhenAll <T>( this IEnumerable <T> enumerable, CancellationToken cancelToken, Func <T, int, CancellationToken, Task> func, int?maxParallelization = null) { if (enumerable == null) { throw new ArgumentNullException(nameof(enumerable)); } if (func == null) { throw new ArgumentNullException(nameof(func)); } var exceptions = new ConcurrentQueue <Exception>(); var maxCount = maxParallelization ?? Environment.ProcessorCount; var tasks = new List <Task>(maxCount); using (var enumerator = new EnumeratorInfo <T>(enumerable)) { for (var i = 0; i < maxCount; i++) { T item; int index; if (!enumerator.TryGetNext(out item, out index)) { break; } var task = RunLoopAsync(enumerator, item, index, exceptions, func, cancelToken); tasks.Add(task); } await Task.WhenAll(tasks).ConfigureAwait(false); } if (exceptions.Count > 0) { throw new AggregateException(exceptions); } }