0

Stephen Toubは、彼の記事「タスクベースの非同期パターン」で、タスクベースの非同期パターン(TAP)を実装する非同期メソッドは、UIスレッドなどの特定のスレッドを使用してコードを実行することもできると説明しています。これには、非同期メソッドが呼び出し元のスレッドを使用できることが含まれます。この場合、asyncメソッドは実際には非同期ではなく、呼び出し元のスレッドをブロックします。それは本当に許可されていますか?呼び出し元のスレッドをブロックする非同期メソッドを作成するのは意味がありませんか?

スティーブンの記事の関連する条項は次のとおりです。

対象環境

非同期実行が発生する場所を決定するのは、TAPメソッドの実装次第です。TAPメソッドの開発者は、でワークロードを実行することを選択でき、ThreadPool非同期I / Oを使用して実装することを選択できます。したがって、操作の実行の大部分をスレッドにバインドせずに、特定のスレッドで実行することを選択できます。 UIスレッドなどの必要性、またはその他の潜在的なコンテキスト。TaskTAPメソッドに実行する実行がなく、システムの他の場所での条件の発生を単に表す(たとえば、キュ​​ーに入れられたデータ構造に到達するTask<TData>ことを表す)を返す場合もあります。TData

4

3 に答える 3

1

メソッド(またはその一部)をUIスレッドで実行する必要があるという事実は、UIスレッドから呼び出すかどうかに関係なく、ブロックする必要があることを意味するわけではありません。

Task DownloadAndShowData()一部のデータを非同期的にダウンロードしてUIに表示するメソッドがあるとします。ダウンロードしたデータをUIに表示するには、UIスレッドでコードを実行する必要があります。次のように実装できます。

async Task DownloadAndShowData()
{
    var data = await DownloadData();
    await uiSchedulerFactory.StartNew(() => ShowData(data));
}

uiSchedulerFactoryこれは、 UITaskFactoryスレッドでコードを実行する(を使用してSynchrnonizationContext)です。

このコードではTask、UIスレッドを使用したUIにデータが表示された後にのみ、返されるものが完成します。しかし、メソッド自体はブロックしません。次のようなコードがある場合:

await DownloadAndShowData();
// some more code

UIスレッドで実行すると、にawait到達すると、現在のメソッドが「一時停止」され、UIスレッドが解放されます。ダウンロードが終了ShowData()すると、UIスレッドで上から実行されます(実行可能で、スレッドをブロックするものはありません)。その後、呼び出し元のメソッドは「一時停止されていない」状態で// some more code実行されます。

要約すると、asyncメソッドはUIスレッド(呼び出し元のコードが実行されている場所でもある可能性があります)でいくつかのコードを実行しますが、asyncメソッドはブロックしません。

于 2012-08-12T13:13:08.420 に答える
0

awaitオブジェクトを返すメソッドの呼び出しTaskは、そのタスクオブジェクトに委任して、そのタスクの呼び出しを開始するだけです。そのタスクオブジェクトの呼び出し元から、そのタスクオブジェクトはすでに呼び出されている場合とされていない場合があります。すでに呼び出されているawait場合は、到達するまでに完了する可能性があります。その場合、awaitの観点から、タスクは同期的に実行されます。

それは1つのインスタンスです。もう1つは、Task何をする必要があるかを知っているということです。それがする必要があることを同期的にもっと速くすることができれば、それは単に同期的にそれをするでしょう。一例として、リモートソースからデータを受信する場合があります。データを受信する多くのメソッドはTAPを実装します。これは、データがリモートソースによって送信され、バックグラウンドでコンピューターによって受信されるためです。「非同期に」バイトを受信するメソッドを呼び出すと、すでにそのバイトが含まれている可能性があり、同期的にバイトを返す方が簡単です。まだバイトが受信されていない場合、メソッドは非同期で実行され、リモートソースからバイトが送信されるのを待ちます。そのバイトが受信されると、継続または。に続くコードを介して非同期的に呼び出し元に通知されますawait

于 2012-08-12T16:19:31.173 に答える
-1

私の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メソッドがその後も続く場合awaitTaskデフォルトでは同じコンテキストで再開されます。この「コンテキスト」は、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メソッドで使用します。

于 2012-08-12T15:19:09.577 に答える