0

非同期/待機機能を最大限に活用して、多数の同時(またはネストされた)タスクを生成するMicrosoft.NETFrameworkアプリケーションについて考えてみます。重要な「フロー」制御はありません。つまり、タスクはほとんど独立しており、互いに完了するのを待たずに、すべてが実行を競います。

タスクをスケジュールまたは実行する方法とタイミング、およびどのスレッドで決定するかを決定するフレームワークコンポーネントは何ですか?

ユーザーコードからそのメカニズムに影響を与える可能性のあるコースは何ですか?

編集
私は私の質問がどこに向けられているかを特定する良い文章を見つけました:

コードがawaitableを待機し、その待機者がまだ完了していないと言った場合(つまり、待機者のIsCompletedがfalseを返す場合)、メソッドは一時停止する必要があります...

ここで説明する時点は、私の質問から1ステップ遅れています。何かがすでにユーザーコードを処理し、awaitableawaiterを構築し、コンテキストをキャプチャして、タスクを実行する(またはすでに実行している)スレッドを決定している可能性があります。私はその「何か」について尋ねています。

ユーザーコードがフレームワークがたどるルートにどのように影響するかはわかりますが、それらはプログラマー側の外部の「知識に基づいた」決定です。私たちが影響を及ぼし、それを過飽和にする可能性のある各ルートをとるとします...私たちはいくつかの施設に大きな打撃を与えていますよね?たぶん一文の答えはありません...そして、以下の@Stephenの答えでそれを見るのが遅い場合は申し訳ありません-私はあなたの助けに感謝し、掘り続けます。

(関連するトピックのいくつかは、スレッドプール、コンテキストなど、同期/待機の要約の下でより深くなるようです。私はその方向に掘り下げるのですか?)
編集を終了

カスタムTaskSchedulerは(最良の)(唯一の)答えですか?

質問の目的上、リソースの不足(ネットワーク、I / Oの飽和)やビジネス上の理由(人為的な制限)など、スロットルに関する外部の考慮事項は無視します。または、何が実行されているかを追跡しようとするなどして、ユーザーコードのスロットリングをハックします。

4

1 に答える 1

2

同時(親子関連)タスク。

あるasyncメソッドが別のメソッドを呼び出す場合、それらのタスクは「親/子」の関係と考えることができます。ただし、技術的には、親子タスクの関係はありません。

スケジューリング、スレッド化、実行を制御するフレームワークコンポーネントとは何ですか?

これについては、MSDNのドキュメント(「Awaitで実行を一時停止する」の下)my async/ awaitintroで説明されています。asyncメソッドがを介して一時停止するとawait、デフォルトでは、現在SynchronizationContext(または現在TaskSchedulerがない場合は現在SynchronizationContext)をキャプチャし、それを使用してメソッドを再開します。これがデフォルトの動作です。どのasyncメソッドも、の結果を使用して、キャプチャされたコンテキストで再開しないことを選択できます。ほとんどの場合、これによりスレッドプールでメソッドの継続が実行されます。awaitConfigureAwait(false)

最初に考慮すべきことは、可能なConfigureAwait(false)限りどこにでも適用することです。これを一貫して行う場合、継続はほとんどの場合スレッドプールによって管理され、利用可能なリソースを最適に利用します。手動によるスロットルは実際には必要ありません。

そうは言っても、それを行うにはいくつかの方法があります。

TaskScheduler

を使用して、継続TaskSchedulerの実行を制御できます(使用しない場合)。このレベルのスケジューリングでのスロットリングまたは相互排除に使用できます。ただし、@ svickが指摘したように、タスクスケジューラは、各メソッドの個々の(同期)部分のみを「参照」します。したがって、これは多くの場合、人々が探している解決策ではありません。asyncConfigureAwait(false)ConcurrentExclusiveSchedulerPairasync

TPLデータフロー

粗粒度の操作(必要に応じて「子」操作をいくつでも実行できます)の調整に主に関心がある場合は、 TPLデータフローActionBlockからを使用してそれを行うことができます。

var block = new ActionBlock<Func<Task>>(f => f(),
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = ...; });
block.Post(MyMethodAsync);
...

TaskSchedulerアプローチとは異なり、MaxDegreeOfParallelismTPL Dataflowはasync、すべての「子」タスクと継続を含め、メソッド全体を考慮します。

TPL Dataflowの使用を開始すると、アプリのロジックの他の部分もより自然に表現されることに気付く場合があります。

AsyncSemaphore

スロットリングのニーズがより複雑な場合は、別のアプローチがあります。これは、私のAsyncExライブラリAsyncSemaphoreで利用できます。スロットルする必要のある各メソッドは、で実行を開始し、で完了します。これらの呼び出しを選択した場所に配置することで、抑制される範囲を完全に制御できます。asyncawait WaitAsyncRelease

于 2013-03-17T14:54:50.193 に答える