私のasync/awaitイントロ、特に「コンテキスト」について説明している部分が役立つかもしれません。
一般的な例は、いくつかの情報をダウンロードし、それをデータ構造に解析してから、次のようにUIを更新することです。
private async Task GetInfoAndUpdateUIAsync()
{
var info = await GetInfoAsync();
UpdateUI(info);
}
private async Task<MyInfo> GetInfoAsync()
{
using (var client = new HttpClient())
{
var httpResponse = await client.GetStringAsync(...);
return MyInfo.Parse(httpResponse);
}
}
ウォークスルー
GetInfoAndUpdateUIAsyncUIコンテキスト(async voidイベントハンドラーなど)から呼び出すことができます。
実行をGetInfoAndUpdateUIAsync開始すると、UIスレッドで(同期して)実行されます。最初に行うことは、を呼び出すことGetInfoAsyncです。
GetInfoAsyncまた、UIスレッドで(同期的に)実行を開始します。を作成しHttpClient、それを使用してURLからのデータのダウンロードを開始します。をGetInfoAsync実行するawaitと、状態が保存され、不完全ながに返さTask<MyInfo>れGetInfoAndUpdateUIAsyncます。
GetInfoAndUpdateUIAsync返さawaitれたに対してを実行しますがTask<MyInfo>、これは完全ではありません。したがって、状態も保存して戻ります。async voidこれは、元の呼び出し元(たとえば、イベントハンドラー)にバックアップし続けます。UIスレッドは、他の作業を自由に行えるようになりました。
データのHttpClientダウンロードが完了すると、返さTask<string>れるデータは完了します。GetInfoAsyncこれにより、UIスレッドでの継続がスケジュールされます。
GetInfoAsyncその後、UIスレッドで実行を継続します。UIスレッドで実行している間、応答をデータ構造()に解析し、メソッドの最後に到達して、以前に返されMyInfo.Parseたタスクを完了します。Task<MyInfo>
完了すると、UIスレッドへTask<MyInfo>の継続をスケジュールします。次に、UIスレッドで(同期的に)呼び出します。GetInfoAndUpdateUIAsyncGetInfoAndUpdateUIAsyncUpdateUI(info)
結論
これは、asyncメソッドのさまざまな部分がUIスレッドで(同期的に)実行されるが、UIスレッドがブロックされていない例です。
asyncメソッドがその後も続く場合await、Taskデフォルトでは同じコンテキストで再開されます。この「コンテキスト」は、SynchronizationContextnullでない場合は現在(UIコンテキストなど)であり、そうでない場合は現在TaskSchedulerです。の結果を待つことでデフォルトの動作をオーバーライドできますConfigureAwait(false)。これにより、メソッドの継続がスレッドプールスレッドで実行されます。
もう1つのメモ
この例では、UIスレッドで実際に実行する必要のないいくつかのことをUIスレッドで実行しています。特に、HTTP応答のMyInfo構造への解析。
GetInfoAsyncデフォルトのコンテキストキャプチャをオーバーライドすることで、もう少し効率的に変更できます。
private async Task<MyInfo> GetInfoAsync()
{
using (var client = new HttpClient())
{
var httpResponse = await client.GetStringAsync(...).ConfigureAwait(false);
return MyInfo.Parse(httpResponse);
}
}
これで、HTTP応答が着信してGetInfoAsync実行を継続すると、UIスレッドではなくスレッドプールスレッドで実行を継続します。したがってMyInfo.Parse、UIではなくスレッドプールで実行されます。解析Task<MyInfo>が完了すると、が完了GetInfoAndUpdateUIAsyncし、UIスレッドで実行を継続します。
UIスレッドで実行する必要がGetInfoAndUpdateUIAsyncあるため、で同じことを行うことはできません。UpdateUI
したがって、これはベストプラクティスにつながります。 ConfigureAwait(false)「ライブラリ」asyncメソッドで使用します。