2011-12-30 70 views
0

在這裏,我附上了我用於性能測試的示例。爲什麼所有這些之間有太多的區別? (這是示例控制檯應用程序)爲什麼在任務,線程和線程池之間有太多的性能差異?

class Program 
    { 
    internal class ThreadObj 
     { 
     public ManualResetEvent signalComplete { get; set; } 
     public int TaskItem { get; set; } 
     } 

    static void ThreadWork(object o) 
     { 
     ThreadObj obj = (ThreadObj)o;   
     System.Threading.Thread.Sleep(5000);    
     obj.signalComplete.Set(); 
     } 
    static void Main(string[] args) 
     { 
     // Using new .net 4.0 Task 
     Stopwatch watch = new Stopwatch(); 
     watch.Start(); 
     System.Collections.Concurrent.ConcurrentBag<Task> tasks = new System.Collections.Concurrent.ConcurrentBag<Task>(); 
     Parallel.For(0, 60, i => 
     { 
      Task t = Task.Factory.StartNew(() => 
      {      
       System.Threading.Thread.Sleep(5000);      
      }, TaskCreationOptions.PreferFairness); 
      tasks.Add(t); 
     }); 
     Console.WriteLine("Waiting for task to finish"); 
     Task.WaitAll(tasks.ToArray()); 
     watch.Stop(); 
     Console.WriteLine("Complete(Tasks) : Time " + watch.ElapsedMilliseconds.ToString());   



     // Using Thread 
     watch.Reset(); 
     watch.Start(); 
     System.Collections.Concurrent.ConcurrentBag<ManualResetEvent> tasksThreads = new System.Collections.Concurrent.ConcurrentBag<ManualResetEvent>(); 
     Parallel.For(0, 60, i => 
     { 
      ManualResetEvent signal = new ManualResetEvent(false); 
      tasksThreads.Add(signal); 
      Thread t = new Thread(new ParameterizedThreadStart(ThreadWork)); 
      t.Start(new ThreadObj() { signalComplete = signal, TaskItem = i }); 
     }); 
     Console.WriteLine("Waiting for task to finish"); 
     WaitHandle.WaitAll(tasksThreads.ToArray()); 
     watch.Stop(); 
     Console.WriteLine("Complete(Threads) : Time " + watch.ElapsedMilliseconds.ToString()); 


     // Using ThreadPool 
     watch.Reset(); 
     watch.Start(); 
     System.Collections.Concurrent.ConcurrentBag<ManualResetEvent> tasksThreadPools = new System.Collections.Concurrent.ConcurrentBag<ManualResetEvent>(); 
     Parallel.For(0, 60, i => 
     { 
      ManualResetEvent signal = new ManualResetEvent(false); 
      tasksThreadPools.Add(signal); 
      ThreadObj obj = new ThreadObj() { signalComplete = signal, TaskItem = i }; 
      ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWork), obj); 
     }); 
     Console.WriteLine("Waiting for task to finish"); 
     WaitHandle.WaitAll(tasksThreadPools.ToArray()); 
     watch.Stop(); 
     Console.WriteLine("Complete(ThreadPool) : Time " + watch.ElapsedMilliseconds.ToString()); 
     Console.ReadLine(); 
     } 

    } 

請在此提供您的建議。

這裏是我得到的示例輸出。

Waiting for task to finish 
Complete(Tasks) : Time 28050 
Waiting for task to finish 
Complete(Threads) : Time 5435 
Waiting for task to finish 
Complete(ThreadPool) : Time 15032 
+0

您正在看到線程池調度程序正在執行其工作。防止有更多的線程運行,比你有cpu核心。你的代碼沒有使用Thread來完成,它們都在同一時間運行。消耗60兆字節的虛擬內存。使用TaskCreationOptions.LongRunning在這裏是有保證的,五秒很長時間,你不關心公平。 – 2011-12-30 11:27:21

回答

2

你的測試案例離實驗還很遠。當你在threadWork方法中執行實際的計算工作時,你會發現結果是非常不同的。 TPL在內部使用線程池,所以這是Threadpool vs Threads的問題。與Threadpool相比,TPL有如此不同的原因可能在於Threadpool本身的性質(稍後會回來)。

看看線程完成的時間。你的測試方法只休眠5秒,就是這樣。現在,其他43秒的時間在哪裏?正確的,創建和銷燬線程本身和相關的開銷,包括上下文切換。線程池有一個可以同時執行的線程隊列。這取決於線程池,它的配置可以在需要時創建和銷燬額外的線程。當您在線程池中計劃60個項目時,線程池不會同時創建60個線程來同時處理所有項目,而是使用該線程的一小部分並處理每個線程的多個項目。既然你的測試方法只是在睡覺,這就解釋了花費在線程上的時間和花在Threadpool上的時間之間的巨大差異。

由於TPL在內部使用Threadpool,並且在您運行ThreadPool測試之前,因此在邏輯上假設在該階段:Threadpool中的線程較少,但由於運行了TPL,爲Threadpool創建,反過來,當你的Threadpool測試運行時,最初有更多的線程可用,這就解釋了TPL和Threadpool之間的區別。

實際上,您希望儘可能使用線程池,特別是對於計算操作。當您需要與外部資源同步時,例如從網絡下載某些內容時,我建議不要使用線程,而要使用.NET中更高級的異步選項之一來獲取該特定資源。

相關問題