Async/await自体は並行性/並列性とは関係がなく、継続渡しスタイル(CPS)の実装にすぎないというのは正しいですか?そして、実際のスレッド化は、SynchronizationContext
が通過/復元するawait
インスタンスによって実行されますか?
それが正しければ、SynchronizationContext
について次の質問があります。
継続が同じスレッドで実行されることを保証します。
ただし、スレッドのコンテキスト情報が保持されるという保証はありますか? Name
、CurrentPrincipal
、CurrentCulture
、CurrentUICulture
などを意味します。フレームワーク(ASP.NET、WinForms、WCF、WPF)に依存しますか?
Async/await自体は並行性/並列性とは関係がなく、CPSの実装にすぎないというのは正しいですか?
さて、async
/await
はCPSを使用した書き直しなので、コアの理解は正しいです。
「並行性」と「並列性」に関しては、並行性が可能になると言えます。すべて「飛行中」の複数のasync
操作を同時に開始できます。これは、_Task.WhenAll
_および_Task.WhenAny
_を使用して簡単に実行できます。
また、async
自体は「マルチスレッド」を意味しませんが、_Task.Run
_は簡単なasync
互換のマルチスレッドを有効にします。
そして、実際のスレッド化は、パス/復元を待機するSynchronizationContextインスタンスによって実行されますか?
このように考えてください。CPSの書き換えによって作成された継続は、どこかで実行する必要があります。キャプチャされた「非同期コンテキスト」を使用して、継続をスケジュールできます。
補足:キャプチャされたコンテキストは、null(---)でない限り、実際には_SynchronizationContext.Current
_です。nullの場合、キャプチャされたコンテキストは_TaskScheduler.Current
_です。
もう1つの重要な注意事項:コンテキストのキャプチャと復元は、実際には「awaiter」オブジェクト次第です。したがって、デフォルトでは、await
a Task
(またはその他の組み込みの待機可能ファイル)を使用すると、コンテキストがキャプチャされて復元されます。ただし、ConfigureAwait(false)
の結果をawait
した場合、コンテキストはキャプチャされません。同様に、あなたがあなた自身のカスタムをawait
待っている場合、それはコンテキストをキャプチャしません(あなたがそれをプログラムしない限り)。
ただし、スレッドのコンテキスト情報が保持されるという保証はありますか?名前、CurrentPrincipal、CurrentCulture、CurrentUICultureなどを意味します。
SynchronizationContext
はExecutionContext
とは異なります。簡単な答えは、ExecutionContext
は常に「流れる」ので、CurrentPrincipal
が流れるということです(そうでない場合は、セキュリティの問題である可能性があります。そのため、APIが流れないのはExecutionContext
は常にUnsafe
で終わります)。
UIアプリでは、カルチャは流れませんが、デフォルトでは、とにかくすべてのスレッドで同じです。 Name
は、同じスレッドで再開しない限り(たとえば、UI SynchronizationContext
を使用して)、確実に流れません。
さらに読むために、私は自分自身の async
/await
チュートリアル から始めてから 公式async
/await
FAQ 。次に、 ExecutionContext
とSynchronizationContext
に関するStephenToubのブログ投稿をご覧ください。
私の SynchronizationContext
article も役に立ちます。
いいえ、async
/await
キーワードは並行性と関係があります。 async
/await
は基本的に、メソッドコードをタスクと継続にラップします。コンパイラーが(タスク並列ライブラリーを使用して)生成する正確な変換を確認するには、コードスニペットを逆アセンブルします。 async
/await
の使用法のこの翻訳は、以下の例と「類似」しています(ただし同一ではありません!)。
async Task<int> TaskOfTResult_MethodAsync()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
これはおおよそに変換されます
private int Result()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
次のようなメソッドの外で戻るのを待つ場所
int? hours = null;
Task<int> task = null;
task = Task.Factory.StartNew<int>(() => Result());
task.ContnueWith(cont =>
{
// Some task completion checking...
hours = task.Result;
}, CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Current);
または、TPLコードをResult
メソッドに配置することもできます
private int ResultAsync()
{
int? hours = null;
Task<int> task = null;
task = Task.Factory.StartNew<int>(() =>
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}, CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Current);
try
{
return task.Result;
}
catch (AggregateException aggEx)
{
// Some handler method for the agg exception.
aggEx.Handle(HandleException);
}
}
SynchronizationContext
は、async
/awate
コードの同じスレッドで継続が実行されることを保証しません。ただし、SynchronisationContex
キーワードを使用して、TPLコードを使用してコンテキストを設定できます。