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で実装したもので、以下の場所に完全なコードがある。