プロデューサー/コンシューマーパターンをc#で実装しようとしました。共有キューを監視するコンシューマースレッドと、共有キューにアイテムを配置するプロデューサースレッドがあります。プロデューサースレッドは、データを受信するようにサブスクライブされています...つまり、イベントハンドラーを持ち、OnDataイベントが発生するのを待ちます(データはサードパーティAPIから送信されています)。データを取得すると、コンシューマが処理できるようにキューに貼り付けます。
OnDataイベントがプロデューサーで発生すると、プロデューサースレッドで処理されると予想していました。しかし、それは起こっていることではないようです。 OnDataイベントは、新しいスレッドで処理されているように見えます!これは.netが常に機能する方法ですか?イベントは独自のスレッドで処理されますか?イベントが発生したときにどのスレッドがイベントを処理するかを制御できますか?数百のイベントがほぼ同時に発生した場合...それぞれに独自のスレッドがありますか?
質問を読み直した後、私は問題を今理解したと思います。基本的に次のようなものがあります。
class Producer
{
public Producer(ExternalSource src)
{
src.OnData += externalSource_OnData;
}
private void externalSource_OnData(object sender, ExternalSourceDataEventArgs e)
{
// put e.Data onto the queue
}
}
そして、そのキューからものを引き出すコンシューマスレッドがあります。問題は、OnDataイベントがExternalSource
オブジェクトによって実行されていることです-実行中のスレッドで発生します。
C#event
sは基本的に使いやすいデリゲートのコレクションであり、イベントを「発生」させると、ランタイムがすべてのデリゲートをループし、一度に1つずつ発生させます。
したがって、OnDataイベントハンドラは、ExternalSource
が実行されているスレッドで呼び出されます。
自分でマーシャリングを行わない限り、イベントはそれを呼び出しているスレッドで実行されます。イベントが呼び出される方法について特別なことはなく、プロデューサースレッドにはイベントハンドラーがありません。プロデューサースレッドは単に「このイベントを起動したら、この関数を呼び出す」と言いました。イベントの実行をアタッチするスレッドでも、それ自体のスレッドでも発生させる原因は何もありません(通常、イベントのデリゲートを呼び出すのではなくBeginInvoke
を使用する場合を除きますが、これは単にThreadPool
で実行します)。
Invoke
を使用してイベントを発生させることは、メソッドを呼び出すことと同じです。イベントを発生させたのと同じスレッドで実行されます。
BeginInvoke
を使用してイベントを発生させるには、ThreadPool
を使用します。ここにいくつかあります マイナーな詳細