public static Func <Task> ForEach <T>(IQueueSource <T>[] sources, InputPriorities inputPriorities, Func <ForEachInfo <T>, Task> processAsync, Func <Task> onCloseAsync, ExceptionCollector ec) { Func <Task> t = async delegate { try { int sourceCount = sources.Length; bool[] atEof = new bool[sourceCount]; RoundRobinLoopGenerator loop = new RoundRobinLoopGenerator(sourceCount, inputPriorities); while (!(atEof.All(e => e))) { var ops = Utils.OperationStarters <int, Option <T> >(); loop.ForEach ( j => { ops = ops.AddIf(!atEof[j], j, Utils.StartableGet <T, Option <T> >(sources[j], a => new Some <T>(a), new None <T>())); } ); Tuple <int, Option <T> > result = await ops.CompleteAny(ec.CancellationToken); if (result.Item2.HasValue) { try { await processAsync(new ForEachInfo <T>(result.Item2.Value, result.Item1, 0, ec.CancellationToken)); } catch (Exception exc) { ec.Add(exc); } } else { atEof[result.Item1] = true; } } } finally { if (onCloseAsync != null) { try { await onCloseAsync(); } catch (Exception exc) { ec.Add(exc); } } } }; return(t); }
/// <summary> /// ParallelForEach /// </summary> /// <param name="sources"></param> /// <param name="inputPriorities"></param> /// <param name="parallelWorker"></param> /// <param name="processAsync"></param> /// <param name="onCloseAsync"></param> /// <param name="ec"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Func <Task> ParallelForEach <T>(IQueueSource <T>[] sources, InputPriorities inputPriorities, ParallelWorker parallelWorker, Func <ForEachInfo <T>, Task> processAsync, Func <Task> onCloseAsync, ExceptionCollector ec) { Func <Task> t = async delegate { IdleDetector idleDetector = new IdleDetector(); try { int sourceCount = sources.Length; bool[] atEof = new bool[sourceCount]; RoundRobinLoopGenerator loop = new RoundRobinLoopGenerator(sourceCount, inputPriorities); while (!(atEof.All(e => e))) { var ops = Utils.OperationStarters <int, Optional <T> >(); loop.ForEach ( j => { ops = ops.AddIf(!atEof[j], j, Utils.StartableGet <T, Optional <T> >(sources[j], a => new Some <T>(a), Optional <T> .None())); } ); Tuple <int, Optional <T> > result = await ops.CompleteAny(ec.CancellationToken); if (result.Item2.HasValue) { int sourceIndex = result.Item1; T itemValue = result.Item2.Value; idleDetector.Enter(); await parallelWorker.StartWorkItem ( async workerId => { try { await processAsync(new ForEachInfo <T>(itemValue, sourceIndex, workerId, ec.CancellationToken)); } catch (Exception exc) { ec.Add(exc); } finally { idleDetector.Leave(); } }, ec.CancellationToken ); } else { atEof[result.Item1] = true; } } } finally { if (onCloseAsync != null) { try { await onCloseAsync(); } catch (Exception exc) { ec.Add(exc); } } } }; return(t); }