2012-02-15 43 views
1

這裏是我曾經用過的代碼示例:力Parallel.ForEach使每個項目一個線程收集

 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秒鐘的

我會改過來:

  • 創建大量的等待句柄
  • 然後開始阻止剩下的一秒

在最簡單的(僞代碼):

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 2012-02-15 08:47:08

+0

@ kseen你應該仍然可以WaitOne上看看它是否完成;如果是這樣,請使用EndConnect – 2012-02-15 09:10:06