2012-02-15 8 views
1

は、ここで私が使用しているコードのサンプルです:フォースParallel.ForEachは、コレクション内の項目ごとに1つのスレッドを作る

 Stopwatch s = new Stopwatch(); 
     s.Start(); 

     ParallelOptions po = new ParallelOptions(); 
     // hosts contain 23 items 
     po.MaxDegreeOfParallelism = hosts.Count(); 

     Parallel.ForEach(hosts, po, p => 
      { 
       using (TcpClient tcpClient = new TcpClient()) 
       { 
        IAsyncResult result = tcpClient.BeginConnect(p.Value, 80, null, null); 
        WaitHandle timeoutHandler = result.AsyncWaitHandle; 
        try 
        { 
         if (!result.AsyncWaitHandle.WaitOne(1000, false)) 
         { 
          tasks.TryAdd(p.Key, new TaskCompleteResult { result = false, exc = new Exception("By timeout") }); 
          tcpClient.Close(); 
         } 
         else 
         {        
          tasks.TryAdd(p.Key, new TaskCompleteResult { result = true, exc = null }); 
         } 

         tcpClient.EndConnect(result); 
        } 
        catch (Exception ex) 
        { 
         tasks.TryAdd(p.Key, new TaskCompleteResult { result = false, exc = ex }); 
        } 
        finally 
        { 
         timeoutHandler.Close(); 
        } 
       } 
      }); 

     s.Stop(); 
     Console.WriteLine(s.Elapsed.TotalSeconds); 

だから、私たちは注意一部に取れば、それは、私の1(または多分2を与えるだろうと思ってオーバーヘッド作業)秒ですが、4秒かかります。 Parallel.ForEachは、スレッドプールの前に用意されているスレッドからスレッドを取り出したり、新しいスレッドを作成したりしますか? 1-2秒の作業はどのように達成できますか?

答えて

3

スレッドは、制約がCPUの場合にのみ有効です。あなたがやっているのは、たくさんのスレッドを持っていることです。個別には何もしておらず、何もしていません。

私はこれと非常に異なる方法でアプローチします。あなたが今やっていることは次のとおりです。

  • は待ちハンドルを作成し、最大1秒

用ブロックが、私はそれを好転でしょうそれぞれのスレッド

  • の多くを作成します
    • 多くの待機ハンドルを作成する
    • 次にブロックを開始する残るものは 1秒最も簡単な(擬似コード)で

    :関与

    WaitHandle[] handles = ... start all the async tasks... 
    Thread.Sleep(1000); 
    foreach(handle) 
        handle.WaitOne(0) ... log result 
    

    しかし、おそらく何か:また

    WaitHandle[] handles = ... start all the async tasks... 
    System.Threading.WaitHandle.WaitAll(handles, 1000); 
    foreach(handle ...) 
        handle.WaitOne(0) ... log result 
    

    :あなたはnew TimeoutException()new Exception("By timeout")を置き換えることを検討することがあります。

  • +0

    素敵なトリック!しかし、例外が発生したと判断するにはどうしたらいいですか?(ここではcatch(Exception ex){tasks.TryAdd(p.Key、new TaskCompleteResult {result = false、exc = ex});} ')それとも、私が気にするべきことは何もないのですか? – kseen

    +0

    @kseenあなたはそれが終わったかどうかを見るためにまだWaitOneにできるはずです。使用している場合は、EndConnectを使用します –

    関連する問題