.NET Framework 4からサポートされるParallel.ForEachと同じようなメソッドを、ThreadPool.QueueUserWorkItemメソッドを使って実装する。
using System;
using System.Collections.Generic;
#if LINQ
using System.Linq;
#endif
using System.Threading;
public static class Parallel {
public static void ForEach<TSource>(/*this*/ IEnumerable<TSource> enumerable, Action<TSource> action)
{
if (enumerable == null)
throw new ArgumentNullException("enumerable");
#if LINQ
var count = enumerable.Count();
#else
var count = 0;
if (enumerable is System.Collections.ICollection) {
count = (enumerable as System.Collections.ICollection).Count;
}
else {
var enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
count++;
}
#endif
if (count == 0)
return;
else if (action == null)
throw new ArgumentNullException("action");
using (var wait = new AutoResetEvent(false)) {
foreach (var e in enumerable) {
ThreadPool.QueueUserWorkItem(delegate(object state) {
try {
action((TSource)state);
}
finally {
if (Interlocked.Decrement(ref count) == 0)
wait.Set();
}
}, e);
}
wait.WaitOne();
}
}
}
サンプルと実行例
public class Test {
static void Main(string[] args)
{
Console.WriteLine("Environment.ProcessorCount: {0}", Environment.ProcessorCount);
int maxWorkerThreads, maxCompletionPortThreads;
ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);
Console.WriteLine("maxWorkerThreads: {0}", maxWorkerThreads);
Console.WriteLine("maxCompletionPortThreads: {0}", maxCompletionPortThreads);
Console.WriteLine();
Parallel.ForEach(new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, delegate(int i) {
Console.WriteLine("started {0}", i);
Thread.Sleep((new Random(unchecked((int)(Environment.TickCount * i)))).Next(5, 25) * 200);
Console.WriteLine("finished {0}", i);
});
Console.WriteLine("done");
}
}
環境1: Ubuntu 9.04 + Mono プロセッサ数=2
$ gmcs pfe.cs -define:LINQ && mono pfe.exe Environment.ProcessorCount: 2 maxWorkerThreads: 40 maxCompletionPortThreads: 20 started 1 started 0 started 2 started 3 started 4 started 9 started 5 started 6 started 7 started 8 finished 4 finished 6 finished 2 finished 5 finished 8 finished 1 finished 7 finished 3 finished 0 finished 9 done
環境2: Windows XP + .NET Framework プロセッサ数=1
D:\>csc pfe.cs -define:LINQ && pfe.exe Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1 for Microsoft (R) .NET Framework version 3.5 Copyright (C) Microsoft Corporation. All rights reserved. Environment.ProcessorCount: 1 maxWorkerThreads: 250 maxCompletionPortThreads: 1000 started 0 started 1 started 2 started 3 started 4 started 5 started 6 finished 0 started 7 finished 1 started 8 started 9 finished 3 finished 4 finished 2 finished 9 finished 7 finished 8 finished 5 finished 6 done