/// <summary> /// Executes each of the provided actions inside a discrete, asynchronous task. /// </summary> /// <param name="actions">An array of actions to execute.</param> /// <exception cref="ArgumentException">The actions array contains a null element.</exception> /// <exception cref="AggregateException">An action threw an exception.</exception> internal static void Invoke(params Action[] actions) { // create a job for each action var tasks = new Task[actions.Length]; for (var i = 0; i < tasks.Length; i++) { Action action = actions[i]; if (action == null) { throw new ArgumentException(String.Format(Resources.ArgumentItemNull, "actions"), "actions"); } tasks[i] = new Task(action); } // run the jobs ThreadQueue.Enqueue(tasks); WaitForTasksToComplete(tasks); CollectExceptions(tasks); }
/// <summary> /// Executes a for each operation on an IEnumerable{T} in which iterations may run in parallel. /// </summary> /// <typeparam name="T">The type of the data in the source.</typeparam> /// <param name="source">An enumerable data source.</param> /// <param name="body">The delegate that is invoked once per iteration.</param> public static void ForEach <T>(IEnumerable <T> source, Action <T> body) { if (body == null) { throw new ArgumentNullException("body"); } // fast forward execution in case parallelization is disabled if (Control.DisableParallelization || ThreadQueue.ThreadCount <= 1 || ThreadQueue.IsInWorkerThread) { foreach (var item in source) { body(item); } return; } // source is a IList, call For instead. if (source is IList <T> ) { var list = (IList <T>)source; For(0, list.Count, i => body(list[i])); return; } var maxBlockSize = IntialBlockSize; var tasks = new List <Task>(); var enumerator = source.GetEnumerator(); while (enumerator.MoveNext()) { var pos = 0; var list = new T[maxBlockSize]; list[pos++] = enumerator.Current; var count = 1; while (count < maxBlockSize && enumerator.MoveNext()) { list[pos++] = enumerator.Current; count++; } var task = new Task( () => { for (var i = 0; i < pos; i++) { body(list[i]); } }); ThreadQueue.Enqueue(task); tasks.Add(task); maxBlockSize = Math.Min(MaxBlockSize, maxBlockSize * ScalingFactor); } if (tasks.Count > 0) { WaitForTasksToComplete(tasks.ToArray()); CollectExceptions(tasks); } }
/// <summary> /// Executes a for each operation on an IEnumerable{TSource in which iterations may run in parallel. /// </summary> /// <typeparam name="TSource">The type of the data in the source.</typeparam> /// <typeparam name="TLocal">The type of the thread-local data.</typeparam> /// <param name="source">An enumerable data source.</param> /// <param name="localInit">The function delegate that returns the initial state of the local data for each thread.</param> /// <param name="body">The delegate that is invoked once per iteration.</param> /// <param name="localFinally">The delegate that performs a final action on the local state of each thread.</param> public static void ForEach <TSource, TLocal>(IEnumerable <TSource> source, Func <TLocal> localInit, Func <TSource, TLocal, TLocal> body, Action <TLocal> localFinally) { if (body == null) { throw new ArgumentNullException("body"); } // fast forward execution in case parallelization is disabled if (Control.DisableParallelization || ThreadQueue.ThreadCount <= 1 || ThreadQueue.IsInWorkerThread) { var localResult = localInit(); foreach (var item in source) { localResult = body(item, localResult); } localFinally(localResult); return; } // source is a IList, call For instead. if (source is IList <TSource> ) { var list = (IList <TSource>)source; For(0, list.Count, localInit, (i, local) => body(list[i], local), localFinally); return; } var maxBlockSize = IntialBlockSize; var tasks = new List <Task <TLocal> >(); var enumerator = source.GetEnumerator(); while (enumerator.MoveNext()) { var pos = 0; var list = new TSource[maxBlockSize]; list[pos++] = enumerator.Current; var count = 1; while (count < maxBlockSize && enumerator.MoveNext()) { list[pos++] = enumerator.Current; count++; } var task = new Task <TLocal>( localData => { var localresult = localData; for (var i = 0; i < pos; i++) { localresult = body(list[i], (TLocal)localresult); } return((TLocal)localresult); }, localInit()); ThreadQueue.Enqueue(task); tasks.Add(task); maxBlockSize = Math.Min(MaxBlockSize, maxBlockSize * ScalingFactor); } if (tasks.Count <= 0) { return; } var taskArray = tasks.ToArray(); WaitForTasksToComplete(taskArray); for (var i = 0; i < taskArray.Length; i++) { localFinally(tasks[i].Result); } CollectExceptions(taskArray); }
/// <summary> /// Executes a for loop in which iterations may run in parallel. /// </summary> /// <typeparam name="T">The type of the thread-local data.</typeparam> /// <param name="fromInclusive">The start index, inclusive.</param> /// <param name="toExclusive">The end index, exclusive.</param> /// <param name="localInit">The function delegate that returns the initial state of the local data for each thread.</param> /// <param name="body">The delegate that is invoked once per iteration.</param> /// <param name="localFinally">The delegate that performs a final action on the local state of each thread.</param> public static void For <T>(int fromInclusive, int toExclusive, Func <T> localInit, Func <int, T, T> body, Action <T> localFinally) { var count = toExclusive - fromInclusive; var tasks = new Task <T> [ThreadQueue.ThreadCount]; var size = count / tasks.Length; // fast forward execution if it's only one or none items if (count <= 1) { if (count == 1) { localFinally(body(fromInclusive, localInit())); } return; } // fast forward execution in case parallelization is disabled if (Control.DisableParallelization || ThreadQueue.ThreadCount <= 1 || ThreadQueue.IsInWorkerThread) { var localresult = localInit(); for (var i = fromInclusive; i < toExclusive; i++) { localresult = body(i, localresult); } localFinally(localresult); return; } // partition the jobs into separate sets for each but the last worked thread for (var i = 0; i < tasks.Length - 1; i++) { var start = fromInclusive + (i * size); var stop = fromInclusive + ((i + 1) * size); tasks[i] = new Task <T>( localData => { var localresult = (T)localData; for (var j = start; j < stop; j++) { localresult = body(j, localresult); } return(localresult); }, localInit()); ThreadQueue.Enqueue(tasks[i]); } // add another set for last worker thread tasks[tasks.Length - 1] = new Task <T>( localData => { var localresult = (T)localData; for (var i = fromInclusive + ((tasks.Length - 1) * size); i < toExclusive; i++) { localresult = body(i, localresult); } return(localresult); }, localInit()); ThreadQueue.Enqueue(tasks[tasks.Length - 1]); if (tasks.Length <= 0) { return; } WaitForTasksToComplete(tasks); foreach (var t in tasks) { localFinally(t.Result); } CollectExceptions(tasks); }