2012-02-07 8 views
1

私はインスタンス化するのに非常に高価なビジネスオブジェクトを持っているとしましょう、私はアプリケーションでそのオブジェクトのインスタンスを10個以上言うことは決してありません。つまり、これは、一度に10以上の並行作業スレッドを実行したくないということです。System.Threading.Tasks.Task内で使用するプライベートオブジェクトインスタンスを作成しますか?

私はこのようなタスクを作成するために、新しいSystem.Threading.Tasksを使用したい:

  1. 作成:

    var task = Task.Factory.StartNew(() => myPrivateObject.DoSomethingProductive()); 
    

    をする方法を示しますそこにサンプルがありますTaskFactoryで使用するための「オブジェクトプール」?

  2. TaskFactoryを指定されたスレッド数に制限しますか?
  3. オブジェクトプール内のインスタンスをロックするので、一度に1つのタスクでしか使用できません。

Igbyの答えはジャスティン・エスリッジからこのexcellent blog postに私を導きました。その後、このサンプルを書くために私を促した:は

using System; 
using System.Collections.Concurrent; 
using System.Threading.Tasks; 

namespace MyThreadedApplication 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // build a list of 10 expensive working object instances 
      var expensiveStuff = new BlockingCollection<ExpensiveWorkObject>(); 
      for (int i = 65; i < 75; i++) 
      { 
       expensiveStuff.Add(new ExpensiveWorkObject(Convert.ToChar(i))); 
      } 
      Console.WriteLine("{0} expensive objects created", expensiveStuff.Count); 
      // build a list of work to be performed 
      Random r = new Random(); 
      var work = new ConcurrentQueue<int>(); 
      for (int i = 0; i < 1000; i++) 
      { 
       work.Enqueue(r.Next(10000)); 
      } 
      Console.WriteLine("{0} items in work queue", work.Count); 
      // process the list of work items in fifteen threads 
      for (int i = 1; i < 15; i++) 
      { 
       Task.Factory.StartNew(() => 
       { 
        while (true) 
        { 
         var expensiveThing = expensiveStuff.Take(); 
         try 
         { 
          int workValue; 
          if (work.TryDequeue(out workValue)) 
          { 
           expensiveThing.DoWork(workValue); 
          } 
         } 
         finally 
         { 
          expensiveStuff.Add(expensiveThing); 
         } 
        } 
       }); 
      } 
     } 
    } 
} 

class ExpensiveWorkObject 
{ 
    char identity; 

    public void DoWork(int someDelay) 
    { 
     System.Threading.Thread.Sleep(someDelay); 
     Console.WriteLine("{0}: {1}", identity, someDelay); 
    } 

    public ExpensiveWorkObject(char Identifier) 
    { 
     identity = Identifier; 
    } 
} 

だから、私は、オブジェクトプールとしてBlockingCollectionを使用しています、そして、彼らは1以上の排他制御を持ってまで、ワーカースレッドは、使用可能な仕事のためにキューをチェックしません。高価なオブジェクトインスタンスの

限定並行処理スケジューラ

することができます:私は

+2

ジョン、ありがとう、私は私がばかだと気付かなかった。 –

+0

あなたは愚かなことについて誰が言ったのですか? –

+0

私は、Parallel Extensions Samples(http://go.microsoft.com/fwlink/?LinkID=165717)のサンプルを試しています。 –

答えて

2

つの思考...これは私の要件を満たしているが、私は本当に良く私よりもこのようなものを知っている人からのフィードバックたい思い並行タスクの数を制限するカスタムタスクスケジューラを使用します。内部的には、nタスクインスタンスを割り当てます。使用可能なインスタンスよりも多くのタスクを渡すと、それらはキューに入れられます。このようなカスタムスケジューラを追加することは、TPLの設計上の特徴です。

Hereは、このようなスケジューラの良い例です。私は正常にこれの修正版を使用しています。

オブジェクトプール

別のオプションは、オブジェクトプールを使用することです。これは非常に似た概念ですが、タスクレベルで制限をかけるのではなく、それをオブジェクトインスタンスの数に置き、タスクが空きインスタンスが利用可能になるのを待つように強制します。これは、オブジェクト作成のオーバーヘッドを減らすという利点がありますが、そのインスタンスがリサイクルできるようにオブジェクトを確実に作成する必要があります。コンシューマは、コンシューマが完了したときにインスタンスをコレクションに戻すConcurrentStackのようなコンシューマ・コンシューマ・コレクションの周りにオブジェクト・プールを作成できます。

+1

+1プールが空のときにタスクを発行しようとしているスレッドは、タスクがプールに返されるまで待つようにBlockingCollectionを使用します。継続は、リサイクルを行うことができます。 –

+0

@Igby、私に正しい方向を指摘してくれてありがとう。 –

+0

@Martin James、上記のサンプルでtry/finallyを使用するよりも、「フェイルセーフ」(またはより良いコーディング慣行)が継続されるでしょうか? –

関連する問題