2009-11-28 3 views
7

IOバインドタスクがあるとします。 WithDegreeOfParallelism = 10とWithExecution = ForceParallelismモードを使用していますが、依然として2つのスレッドしか使用していません。どうして?なぜPLINQは2つのスレッドしか使用しないのですか?

私は通常、PLINQはコア数に等しい並列度を選択することを理解していますが、より高い並列性に対する私の特定の要求はなぜ無視されますか?

static void Main(string[] args) 
{ 
    TestParallel(0.UpTo(8)); 
} 

private static void TestParallel(IEnumerable<int> input) 
{ 
    var timer = new Stopwatch(); 
    timer.Start(); 
    var size = input.Count(); 

    if (input.AsParallel(). 
     WithDegreeOfParallelism(10). 
     WithExecutionMode(ParallelExecutionMode.ForceParallelism). 
     Where(IsOdd).Count() != size/2) 
     throw new Exception("Failed to count the odds"); 

    timer.Stop(); 
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds"); 
} 

private static bool IsOdd(int n) 
{ 
    Thread.Sleep(1000); 
    return n%2 == 1; 
} 
+2

いくつのプロセッサ/コアがありますか? – LukeH

+2

2つ。しかし、具体的には並列度を10と指定しました。 – ripper234

+0

I/Oバウンドタスクがあり、それを複数のスレッドで並列実行するとスピードが向上し、実際にI/Oバインドされていない可能性がありますちょうどひどく書かれていました(たとえば、非同期の代わりに同期を読み込みます)。 –

答えて

8

PLINQは、あなただけのCPUの2つのコアを持っている場合、あなたが持っていた場合は、その数が最も可能性の高い2である、あなたはそれが可能な限り迅速に何をしたいかを実行するスレッドの最適な数を見つけようとします4つのスレッドが表示される可能性が高くなりますが、デュアルコアマシンに4つのスレッドを作成しても、2つのスレッドのみが同時にアクティブになる可能性があるため、パフォーマンスは向上しません。

また、IOベースの操作では、余分なスレッドが実行された最初のIO操作をブロックする可能性があります。

+4

本当に私の質問には答えません - なぜ並列度= 10を特に要求しても、2つのスレッドを使用するのはなぜですか? (更新された質問) – ripper234

+3

@ ripper234:MSDNのドキュメントから: "並列度は、クエリを処理するために使用される同時実行タスクの最大数**です。" 'WithDegreeOfParallelism'は、PLINQが*以上の* n *スレッドを使うべきではないというヒントです。 http://msdn.microsoft.com/en-us/library/dd383719%28VS.100%29.aspx – LukeH

+3

IOバインドされたタスクにPLINQを効果的に使用する方法はありませんか? – ripper234

4

10クエリで を使用する並列度を設定

最大です。並列度は の同時実行の最大数であり、クエリを処理するために使用されます( )。ここから

MSDN

+0

デフォルトでは、PLINQはホストコンピュータ上のすべてのプロセッサを最大** 64 **まで使用します。 WithDegreeOfParallelism(Of TSource)メソッドを使用して、指定した数のプロセッサを使用するようPLINQに指示できます。 http://msdn.microsoft.com/en-us/library/dd383719.aspx –

2

PLINQは、スレッドの数を調整し表示されます。 while(true)ループで上記のコードをラップすると、最初の2回の実行には2秒かかりましたが、3回目以降は1秒しかかかりませんでした。 PLINQは、コアがアイドル状態であり、スレッド数を増やしていることを理解しました。印象的な!

+1

これを行うには、実際にWithDegreeOfParallelismを指定する必要があります。そうしないと、PLINQ自体がマシン上のコア数に制限されます。 – ripper234

0

IO以外は、Roryに同意します。ディスクIOではテストしていませんが、CPUにコアがあるよりも、ネットワークIOがより多くのスレッドでより効果的になる可能性があります。

簡単なテスト(ネットワークの速度が一定でないとして、数回を数え、各スレッドでテストを実行するために、より正確だろうが、それでも)それを証明するために:CDNから500x500pxの画像と

[Test] 
    public void TestDownloadThreadsImpactToSpeed() 
    { 
     var sampleImages = Enumerable.Range(0, 100) 
      .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.") 
      .ToArray();    

     for (int i = 0; i < 8; i++) 
     { 
      var start = DateTime.Now; 
      var threadCount = (int)Math.Pow(2, i); 
      Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount}, 
         index => 
          { 
           using (var webClient = new WebClient()) 
           { 
            webClient.DownloadFile(sampleImages[index], 
                  string.Format(@"c:\test\{0}", index)); 
           } 
          }); 

      Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds); 
     } 
    } 

結果SSDと8コア機を使用した:スレッドの

番号:1、秒:スレッドの25.3904522
を番号:2、秒:スレッドの10.8986233
番号:4、秒:9.9325681
スレッドの数:8、秒:スレッドの3.7352137
番号:16秒:スレッドの3.3071892
番号:32、秒:3.1421797
スレッドの数:64秒:3.1161782
スレッドの数: 128、秒:3.7272132

最終結果は、我々は唯一の100画像:) 8-64スレッドを使用して

時間差をダウンロードする必要があるため、私は最初に考えるような時間はそれほど大きくないがいるが、それはオンになっています8コアマシン。それは2コアマシン(安価なエンドユーザのノートブック)だった場合、私は8スレッドを使用するように強制すると、8コアのマシンで64スレッドを使用するよりも、より大きな影響を与えると思います。

+0

これらの数値を、たとえば10,000回の繰り返しで平均しましたか? – ChrisF

+0

私は、各スレッド数で何度かテストを実行する方が正しいと言いました。とにかく、ポイントは、ネットワークIOを行っている場合に備えて、CPU数が少ないマシン用のスレッドを強制的に追加することです。 – Giedrius

+0

並列オプションが> = 8のために無視されているようです。並列ボディ内にデバッグ出力を追加すると、一度に最大8個しか実行されていないことがわかります。 – crokusek

関連する問題