public static Func <Task> ParallelForEach <T>(IQueueSource <T> source, ParallelWorker parallelWorker, Func <ForEachInfo <T>, Task> processAsync, Func <Task> onCloseAsync, ExceptionCollector ec) { Func <Task> t = async delegate { IdleDetector idleDetector = new IdleDetector(); try { while (true) { var item = await source.Dequeue(ec.CancellationToken); if (!item.HasValue) { break; } T itemValue = item.Value; idleDetector.Enter(); await parallelWorker.StartWorkItem ( async workerId => { try { await processAsync(new ForEachInfo <T>(itemValue, 0, workerId, ec.CancellationToken)); } catch (Exception exc) { ec.Add(exc); } finally { idleDetector.Leave(); } }, ec.CancellationToken ); } } finally { await idleDetector.WaitForIdle(CancellationToken.None); if (onCloseAsync != null) { try { await onCloseAsync(); } catch (Exception exc) { ec.Add(exc); } } } }; return(t); }
/// <summary> /// ParallelWhere /// </summary> /// <param name="queue"></param> /// <param name="parallelWorker"></param> /// <param name="predicate"></param> /// <param name="capacity"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static IQueueSource <T> ParallelWhere <T>(this IQueueSource <T> queue, ParallelWorker parallelWorker, Func <T, Task <bool> > predicate, int?capacity = null) { AsyncQueue <T> outQueue = new AsyncQueue <T>(capacity ?? 2); IdleDetector idleDetector = new IdleDetector(); Func <Task> workPoster = async delegate { while (true) { Optional <T> item = await queue.Dequeue(CancellationToken.None); if (!item.HasValue) { break; } T itemValue = item.Value; idleDetector.Enter(); Task doingWork = await parallelWorker.StartWorkItem ( async (int workerId) => { try { if (await predicate(itemValue)) { await outQueue.Enqueue(itemValue, CancellationToken.None); } } finally { idleDetector.Leave(); } }, CancellationToken.None ); } await idleDetector.WaitForIdle(CancellationToken.None); outQueue.WriteEof(); }; Task.Run(workPoster); return(outQueue); }