2009-10-15T13:20:43の更新内容

programming/tips/paralellforeach_with_queueuserworkitem/index.wiki.txt

current previous
1,148 0,0
+
${smdncms:keywords,Parallel,ForEach,ThreadPool,QueueUserWorkItem,C#}
+
${smdncms:tags,lang/c#,api/.net}
+
*ThreadPool.QueueUserWorkItemを使ってParallel.ForEachを実装する
+
#googleadunit
+

          
+
.NET Framework 4からサポートされるSystem.Threading.Parallel.ForEachと同じようなメソッドを、System.Threading.ThreadPool.QueueUserWorkItemメソッドを使って実装する。
+

          
+
#code(cs){{
+
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
+
      throw new ArgumentNullException("enumerable");
+

          
+
#if LINQ
+
    var count = enumerable.Count();
+
#else
+
    var count = 0;
+

          
+
    if {
+
      count =.Count;
+
    }
+
    else {
+
      var enumerator = enumerable.GetEnumerator();
+

          
+
      while
+
        count++;
+
    }
+
#endif
+

          
+
    if
+
      return;
+
    else if
+
      throw new ArgumentNullException("action");
+

          
+
    using {
+
      foreach {
+
        ThreadPool.QueueUserWorkItem(delegate(object state) {
+
          try {
+
            action((TSource)state);
+
          }
+
          finally {
+
            if
+
              wait.Set();
+
          }
+
        }, e);
+
      }
+

          
+
      wait.WaitOne();
+
    }
+
  }
+
}
+
}}
+

          
+
**サンプルと実行例
+
#code(cs){{
+
public class Test {
+
  public 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");
+
  }
+
}
+
}}
+

          
+
#prompt(環境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
+
}}
+

          
+
#prompt(環境2: Windows XP + .NET Framework プロセッサ数=1){{
+
D:\>csc pfe.cs -define:LINQ && pfe.exe
+
Microsoft Visual C# 2008 Compiler version 3.5.30729.1
+
for Microsoft .NET Framework version 3.5
+
Copyright 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
+
}}