2011-12-30 4 views
0

私はパフォーマンステストに使用した私の例を付けました。なぜこんなに大きな違いがあるのですか? (これはサンプルコンソールアプリケーションです)なぜTasks、Thread、ThreadPoolの間にパフォーマンスの相違があるのですか?

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(); 
     } 

    } 

これにsuggetionを指定してください。

ここに私が得たサンプル出力があります。

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の使用はここで保証されています.5秒は長い時間ですが、公平性は気にしません。 –

答えて

2

あなたはテストケースではありません。 threadWorkメソッド内で実際の計算作業を実行すると、結果が大きく異なることがわかります。 TPLはスレッドプールを内部的に使用しているので、スレッドプール対スレッドの問題です。 TPLがThreadpoolに比べて非常に異なる理由は、Threadpool自体の性質にある可能性が高い(それは後で返される)。

スレッドが完了するのにかかった時間を見てください。あなたのテスト方法は5秒間しか休まず、それだけです。他の43秒はどこに行きましたか?スレッド自体の作成と破棄、およびコンテキスト切り替えを含む関連するオーバーヘッド。スレッドプールには、同時に実行するために使用できるスレッドのキューがあります。それはスレッドプールに任されており、必要と思われるときはいつでも余分なスレッドを作成して破棄することができます。スレッドプールで60個のアイテムをスケジュールすると、スレッドプールは60個のスレッドを作成して、すべてのアイテムを同時に処理することはありませんが、サブスレッドを使用してスレッドごとに複数のアイテムを処理します。テストメソッドは眠っているだけなので、これはスレッドに費やされた時間とスレッドプールで費やされた時間の大きな違いを説明しています。

TPLは内部でThreadPoolテストを実行する前にThreadpoolを使用しているため、その段階でスレッドプールで使用できるスレッドが少なくなっていますが、TPLの実行によりスレッドプールのために作成されたので、あなたのスレッドプールテストが実行されたときに、最初に利用可能なスレッドが増えました.TPLとThreadpoolの違いについて説明しています。

実際には、特に計算操作のために、できるだけスレッドプールを使いたいと思っています。 Webから何かをダウンロードするような外部リソースと同期する必要があるときは、スレッドを使用せず、.NETで利用可能な高度な非同期オプションの1つを使用して特定のリソースを取得することをお勧めします。

関連する問題