private static void _innerTask <TSource>(int i, long total, DateTime started, TSource value, System.Func <TSource, ActionOutputData> action, System.Action <string> logOutputFunc, System.Action <ActionProgressData> progressOutputFunc, string prefix, string postfix, System.Action <Exception, TSource> onExceptionAction, bool cancelOnError, CancellationTokenSource cts, ref long processedCount ) { ActionOutputData cancel = null; try { if (cts.IsCancellationRequested) { return; } try { cancel = action(value); System.Threading.Interlocked.Increment(ref processedCount); if (logOutputFunc != null && !string.IsNullOrEmpty(cancel.Log)) { logOutputFunc(cancel.Log); } if (cancel.CancelRunning) { cts.Cancel(); return; } } catch (Exception e) { if (onExceptionAction == null) { onExceptionAction = (ex, val) => Devmasters.Log.Logger.Root.Error( $"DoActionForAll paraller action error for {Newtonsoft.Json.JsonConvert.SerializeObject(val)}", ex); } if (onExceptionAction != null) { onExceptionAction(e, value); } if (cancelOnError) { cts.Cancel(); return; } } finally { cancel = null; if (progressOutputFunc != null) { ActionProgressData apd = new ActionProgressData(total, processedCount, started, prefix, postfix); progressOutputFunc(apd); } } } catch (Exception e) { if (onExceptionAction == null) { onExceptionAction = (ex, val) => Devmasters.Log.Logger.Root.Error( $"DoActionForAll paraller outside for action error for", ex); } if (onExceptionAction != null) { onExceptionAction(e, default(TSource)); } if (cancelOnError) { cts.Cancel(); } } }
public static void DoActionForAll <TSource, TActionParam>( IEnumerable <TSource> source, System.Func <TSource, TActionParam, ActionOutputData> action, TActionParam actionParameters, System.Action <string> logOutputFunc, System.Action <ActionProgressData> progressOutputFunc, bool parallel = true, int?maxDegreeOfParallelism = null, bool cancelOnError = false, string prefix = null, string postfix = null, System.Action <Exception, TSource> onExceptionAction = null) { if (source == null) { throw new ArgumentNullException("source"); } if (action == null) { throw new ArgumentNullException("action"); } if (prefix == null) { prefix = Devmasters.Log.StackReporter.GetCallingMethod(false, skipNamespaces: new string[] { "Devmasters.Batch" }); } if (maxDegreeOfParallelism.HasValue && maxDegreeOfParallelism.Value == 1) { parallel = false; } DateTime started = DateTime.Now; long processedCount = 0; long total = source.Count(); bool canceled = false; if (parallel) { Core.logger.Debug("Starting parallel TaskManager for {count} items with prefix {prefix}", source?.Count() ?? 0, prefix); CancellationTokenSource cts = new CancellationTokenSource(); try { ParallelOptions pOptions = new ParallelOptions(); if (maxDegreeOfParallelism.HasValue) { pOptions.MaxDegreeOfParallelism = maxDegreeOfParallelism.Value; } pOptions.CancellationToken = cts.Token; Parallel.ForEach <TSource>(source, pOptions, (value) => { ActionOutputData cancel = null; try { cancel = action(value, actionParameters); System.Threading.Interlocked.Increment(ref processedCount); if (logOutputFunc != null && !string.IsNullOrEmpty(cancel.Log)) { logOutputFunc(cancel.Log); } if (cancel.CancelRunning) { cts.Cancel(); } } catch (Exception e) { if (onExceptionAction == null) { onExceptionAction = (ex, val) => Devmasters.Log.Logger.Root.Error( $"DoActionForAll paraller action error for {Newtonsoft.Json.JsonConvert.SerializeObject(val)}", ex); } if (onExceptionAction != null) { onExceptionAction(e, value); } if (cancelOnError) { cts.Cancel(); } } finally { cancel = null; if (progressOutputFunc != null) { ActionProgressData apd = new ActionProgressData(total, processedCount, started, prefix, postfix); progressOutputFunc(apd); } } }); } catch (OperationCanceledException e) { //Catestrophic Failure canceled = true; } } else { Core.logger.Debug("Starting nonparallel TaskManager for {count} items with prefix {prefix}", source?.Count() ?? 0, prefix); foreach (var value in source) { ActionOutputData cancel = action(value, actionParameters); try { System.Threading.Interlocked.Increment(ref processedCount); if (logOutputFunc != null && !string.IsNullOrEmpty(cancel.Log)) { logOutputFunc(cancel.Log); } if (cancel.CancelRunning) { canceled = true; break; } } catch (Exception e) { Devmasters.Log.Logger.Root.Error("DoActionForAll action error", e); if (cancelOnError) { break; } } finally { cancel = null; if (progressOutputFunc != null) { ActionProgressData apd = new ActionProgressData(total, processedCount, started, prefix, postfix); progressOutputFunc(apd); } } } } }