あなたとプロデューサー:消費者物語


完全なサンプルプロジェクトはhereを閲覧できます.

概要
私は最近、私がビルドしようとしていた解決のための適切なアプローチを研究している間、ブロックキングコレクションと製作者消費者パターンにつまずいた.
C Chrount s s blokingCollectionは、適切な状況で使用され、プロデューサーの消費者パターンに適用されるときに、非常に有用なコレクション型です.

どうやって動くの?
通常、あなたはデータを作成するいくつかの記述(生産者)のサービスを持っています.そして、これらの生産者は、データペイロードをブロック収集に預けます.つのブロッキングコレクションは複数の生産者にサービスを提供できます.
ブロック化コレクション内のデータにアクセスするには、通常は「コンシューマー」サービスを使用しますが、通常はブロックを防ぐために通常のタスクで実行されます.この消費者サービスは、プロセスに新たに追加された項目のブロッキングコレクション内の列挙子を常にチェックします.
この列挙体はブロッキングコールですので、バックグラウンドで実行するには、独自のタスク内で実行する必要があります.私たちは、これが後のセクションでどのように働くかについて説明します.
このプロセスは、同じブロックコレクションにデータを追加する3つのプロデューサタスクが存在する、下の図に示します.つのコンシューマータスクは、ブロックのコレクションの列挙子の周りを繰り返し、常に新たに追加された項目を処理します.


サイズ制限
コレクションをインスタンス化するときは、コンストラクタで最大コレクション容量を指定するか、既定のコンストラクターを使用して無限の容量を持つことができます.
たとえば、このスニペットは、最大容量10のコレクションをインスタンス化します.var blockingCollection = new BlockingCollection<int>(10)これは無限大容量コレクションをインスタンス化します.var blockingCollection = new BlockingCollection<int>()この効果は、以下のセクションで追加され、コレクションアイテムを取る上で覆われている.

コレクションアイテムの追加

追加対tryadd
あなたが私のような何かであるならば、2番目のこれらの2つのメソッドがこの命名規則を見るならば、あなたは即座に、text . parse ()とint . tryparse ()のようなものを考えます.
しかし、これらの関数は少し異なります.

追加
add ()はとても簡単ですが、注意してください.次のコードスニペットを考えます.
var blockingCollection = new BlockingCollection<int>(1)

_blockingCollection.ItemCollection.Add(1);
_blockingCollection.ItemCollection.Add(2);

Console.WriteLine("All items added.");
十分に無邪気に見える、右?いいえBlokingCollectionコンストラクターで制限された容量パラメーターを指定したので、コレクションは現在最大容量として' 1 'を持ちます.それで、我々が2つのアイテムを加えるしようとするとき、ここで何が起こりますか?
答えはとても簡単です.最初のadd ()は成功し、' 1 'がコレクションに追加されます.しかし、2番目のadd ()は、コレクションが容量を持つため、スレッドをブロックします.項目がコレクションから削除され、容量制限の下に置かれるまで、2番目のadd ()はブロックし続けます.このコードを使用すると、コンソールのステートメントには到達しません.
解決策?tryadd () !

tryaddする
tryadd ()はadd ()に非常に似たやり方で機能します.1つの主な違い-スレッドをブロックするのをエスケープできます.前のセクションでは、コレクションに制限が置かれている場合にadd ()がどのようにブロックされるかをカバーしました.次の変更コードをその節から考えます.
int additionTimeout = 1000;
var blockingCollection = new BlockingCollection<int>(1)

var firstAdditionSuccess = _blockingCollection.ItemCollection.TryAdd(1, additionTimeout);
var secondAdditionSuccess = _blockingCollection.ItemCollection.TryAdd(2, additionTimeout);

Console.WriteLine("All items added.");
ほとんど同じですか?ここでは、整数、additiontimeoutを宣言し、それをtryaddにパラメータとして渡しました.それは何ですか.
基本的に、コレクションにアイテムを試してみたいですが、コレクションがキャパシティになっている場合は、新しいアイテムを追加しようとしている期間を待つだけです.その期間が超えている場合は、我々は試してみて、アイテムを追加する必要はありません.
本質的に、additiontimeoutは私たちの時間制限です、そして、それが超えられるならば、tryaddはfalseを返して、糸をブロックします.
したがって、上記の例では、コレクションカウントが制限の下にあるので、最初のtryaddは即座に成功します.番目のtryaddは1秒間待ちます、そして、コレクションがまだ能力であるならば、それはfalseを返して、それ自体をブロックします.

コレクション完成
BlockKingCollectionは、実際には、実際には、コレクション内の効果を新しいアイテムを受け入れるのを停止するように指示する必要があります別の作品を動作します.完全にコレクションをマーキングすることにより、新しいアイテムを追加することができますし、任意のブロッキング消費者が解除されます.
完了したコレクションをリセットできないことに注意することは重要です再使用する場合は再インスタンス化する必要があります.
それではどうやってやるの?それは私たちのために素晴らしく、簡単に作られている、我々はちょうど我々のコレクションにoutを呼び出す必要がある、とVoila!今完了です.

消費アイテム
我々が我々のコレクションにアイテムを加える方法を我々がカバーした今、実際に彼らを取り戻すことについてどうですか?次の3つの方法があります.
  • Getconsumingenumerable ()メソッド
  • Take ()メソッド
  • Target ()メソッド
  • おそらく、2つのテイクメソッドが2つの以前にカバーされたaddメソッドとかなり同様に機能すると推測することができます.

    getConsumminGenumerableな
    このメソッドを呼び出すと、あなたのコレクションの項目を反復処理するために使用できるブロック列挙型が返されます.
    しかし、これを使用していくつかのキャッチがあります.次のスニペットを考えてみましょう
    foreach (var item in _myBlockingCollection.GetConsumingEnumerable())
    {
        Console.WriteLine($"Iterating over item {item}");
    }
    
    Console.WriteLine("Enumeration complete!");
    
    さて、他のコレクションと同じように、現在コレクション内の何かを繰り返してループを終了し、最終的なライトライン文をヒットします.いや!実際に起こるのは、列挙子にアクセスするとすぐに、現在のスレッドをブロックします(したがって、別のタスクで消費者を実行することが重要な理由です).それは我々のWrite Lineステートメントを印刷します、そして、それが行くように各々の処理されたアイテムを取り除きます、そして、新しいアイテムが加えられないならば、コレクションが空であるならば、それは糸をブロックして、どんな新しい追加も待つでしょう.
    では、どのようにこのブロッカーをキャンセルするのですか?我々は完全にコレクションをマーキングについて話を覚えていますか?このCompleteAdding()のメソッドを呼び出す必要があります.このポイントでは、コレクションが完全にマークされていることを列挙子に伝え、残りの項目を繰り返し終了すると、アイテムの待機をブロックしません.

    テイク
    add ()メソッドとの類似性のため、ここであまり詳細にはあまり必要がありません.しかし、taker ()は本質的に同じ機能を持ちます.これは、コレクションから単調なアイテムを取るしようとすると、アイテムが存在しない場合はブロックします.

    取水する
    繰り返しますが、あまりにも多くの不必要な詳細に入ることなく、tryKit ()は、メソッドが待機する期間を指定できるtryAdd ()に似たやり方で動作します.

    キーテイクアウト🔑
    BackKingCollectionを使用しないでください.
  • あなたのメインのアプリロジック
  • をブロックするのを防ぐために、あなたの消費者(s)を別々の仕事に走らせてください
  • あなたがデータ
  • を生産し終えたとき、あなたのコレクションを完全にマークするのを忘れないでください
  • は、CompleteAdding()IsAddingCompletedブールプロパティを使用します
    私は、このポストがブロックキングコレクションを使用することに洞察力であることを望みます!