2013-12-19 10 views
5

(デスクトップアプリケーションの)約200.000個のオブジェクトを処理する必要があり、各オブジェクトは処理に約20ミリ秒かかります。これをスピードアップするために、私は同時にそれをしたい。タスク並列ライブラリを使用したスケジューリング

テストのために、私は各オブジェクトを別々のタスクに入れましたが、ジョブのサイズが小さいため、わずかな速度向上しか得られません。だから私の最初の質問は:

これらのオブジェクトの最適なバッチサイズを見つけるための巧妙な(しかしあまりにも複雑ではない)方法がありますか?私は、10,20,100のオブジェクトのバッチでそれらをグループ化するのが最速かどうかについていくつかのローカルテストをすることができたと思いますが、これは少し下位のようです。

2番目(さらに重要):ほとんどのオブジェクトは、CPU時間があるたびに処理する必要があります。しかし、ユーザーは常に10-20個のオブジェクトを見ています。スムーズなユーザーエクスペリエンスを提供するために、キューの前面に常にユーザーが探しているオブジェクトを配置できるようにしたいと考えています。ユーザーは常時ナビゲートしているので、いつも注文をすばやくスケジュールできることが重要だと感じています。 (20 ms * 20は約0.4秒で処理できるはずです)。

これらのオブジェクトを処理するために良いデザインパターンを手伝ってくれる人はいますか?

+0

処理はどのようなことをいっているのですかCPUにバインドされていますか? – svick

+0

_optimal_ wrtバッチサイズを定義する必要があります。最も簡単には、コア/プロセッサの数で項目数を割ります。総スループットは明白な要因ですが、重要なのはユーザーにとっての応答性です。バッチサイズが大きすぎると、ユーザーがバッチ内にあるアイテムを表示したい場合、関連スレッドはそれらのアイテムを配信するには時間がかかりすぎる可能性があります(スレッドが処理されたアイテムを小グループで配信しない限り)。あなたのスレッドは、必要に応じて、アイテムX..Yがキューの先頭に移動しなければならないように、再スケジューリングをサポートすることができます。 – groverboy

+0

'Queue 'は明白なコレクションクラスですが、(SkipWhileのような拡張メソッドを使わない限り)再スケジューリングはサポートしていません。あるいは、 'AddRange'、' RemoveRange'メソッドを持つ 'List 'を使用してください。 – groverboy

答えて

3

オブジェクトがコレクション内にある場合は、Parallel.ForEachまたはParallel.Forを使用できます。あなたのユーザの応答性要件のために、Parallel.Forがより良い選択になるでしょう。

残念ながら、パフォーマンスを測定し、その結果に基づいて戦略を調整することはできません。

+0

あなたはParallel.Forがより良いと思われる理由を説明できますか? – svick

+0

OPの要件は、ユーザーが表示しているすべてのオブジェクトが処理のために優先されることでした。ユーザーがコンテナ内の連続したアイテムを見ていると仮定すると、Parallel.Forはそのアイテムのスライス上で実行できます。 – StevieB

1

項目を並行して処理したいが、順序は気にしない場合は、Parallel.ForEach()(UIスレッドをブロックしないようにバックグラウンドスレッドから呼び出す)を使用してください。

しかし、動的優先度の変更を実装したい場合は、それはもっと複雑になります。

1つの方法では、実行する必要のある単一のアクションを表すJobというオブジェクトを持つことです。次に、ジョブのキューを処理するメソッドがありますが、優先度の高いジョブがあれば実行します。ような何か:

Queue<Job> jobs; 
IEnumerable<Job> priorityJobs; 

void ProcessJobs() 
{ 
    while (true) 
    { 
     Job job = null; 

     lock (jobs) 
     { 
      job = priorityJobs.FirstOrDefault(j => j.NotYetStarted); 

      if (job == null) 
      { 
       do 
       { 
        if (jobs.Count == 0) 
         return; 

        job = jobs.Dequeue(); 
       } while (job.NotYetStarted); 
      } 

      job.NotYetStarted = false; 
     } 

     job.Execute(); 
    } 
} 

あなたはその後、例えば、並列にProcessJobs()を実行するスレッドを開始します:

var tasks = Enumerable.Range(0, Environment.ProcessorCount) 
    .Select(_ => Task.Run(() => ProcessJobs())); 
関連する問題