Advent LINQ (10): .NET 2.0でLINQを使うの回で、比較的簡単にParallel.ForEachを自前で実装出来ると書いたので、例を見せる。
namespace System.Threading.Tasks { public static class Parallel { public static void ForEach<T>(IEnumerable<T> enumerable, Action<T> action) { Debug.Assert(enumerable != null); Debug.Assert(action != null); var exceptionList = new List<Exception>(); using (var wait = new ManualResetEvent(false)) { var count = 1; foreach (var item in enumerable) { Interlocked.Increment(ref count); ThreadPool.QueueUserWorkItem(new WaitCallback(p => { try { try { action(item); } catch (Exception ex) { lock (exceptionList) { exceptionList.Add(ex); } } } finally { if (Interlocked.Decrement(ref count) == 0) { wait.Set(); } } })); } if (Interlocked.Decrement(ref count) == 0) { wait.Set(); } wait.WaitOne(); } if (exceptionList.Count >= 1) { throw new AggregateException(exceptionList); } } public static void Invoke(params Action[] actions) { ForEach(actions, action => action()); } } }
コンパイルを通すには、他にもActionクラスが必要だ。このサンプルはVSCoverageToEmmaで実装したもので、以下の場所に完全なコードがある。