anyこのようなメソッドを書くシナリオがあります:
public async Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return await DoAnotherThingAsync();
}
これの代わりに:
public Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return DoAnotherThingAsync();
}
理にかなっていますか?
内部DoAnotherThingAsync()
呼び出しからreturn await
を直接返すことができる場合にTask<T>
コンストラクトを使用する理由?
return await
を含むコードは非常に多くの場所で見られますが、何かを見逃している可能性があります。しかし、私が理解している限りでは、この場合async/awaitキーワードを使用せず、タスクを直接返すことは機能的に同等です。追加のawait
レイヤーのオーバーヘッドを追加する理由
これを行う唯一の理由は、以前のコードに他のawait
がある場合、または何らかの方法で結果を操作してから結果を返す場合です。それが発生する可能性のある別の方法は、例外の処理方法を変更するtry/catch
を使用することです。あなたがそれを何もしていないなら、あなたは正しい、メソッドasync
を作るオーバーヘッドを追加する理由はありません。
結果を待つ必要がある別のケースは次のとおりです。
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
この場合、GetFooAsync
のタイプは2つのメソッド間で異なり、Task<Foo>
はTask<IFoo>
に直接割り当てることができないため、GetIFooAsync()
はT
の結果を待つ必要があります。 。しかし、結果を待つ場合、それはFoo
になります。これはisが直接IFoo
に割り当て可能です。次に、asyncメソッドは、結果をTask<IFoo>
内に再パッケージし、すぐに離れます。
それ以外の点で単純な「サンク」メソッドを非同期にすると、非同期ステートマシンがメモリに作成されますが、非同期ではありません。非同期バージョンはより効率的であるため(実際には)非非同期バージョンを使用することを指すことがよくありますが、ハングした場合には、そのメソッドが「戻り/継続スタック」に関与しているという証拠もありません。ハングを理解するのが難しくなる場合があります。
そのため、perfが重要でない(通常はそうではない)場合は、これらのすべてのサンクメソッドで非同期をスローして、後でハングを診断し、それらがサンクメソッドは時間の経過とともに進化するため、スローではなくフォールトされたタスクを返すようになります。
Return awaitを使用しない場合は、デバッグ中または例外のログに出力されるときにスタックトレースを台無しにする可能性があります。
タスクを返すと、メソッドは目的を果たし、コールスタックから除外されます。 return await
を使用すると、呼び出しスタックに残ります。
例えば:
Awaitを使用する場合の呼び出しスタック:AはBからのタスクを待機== BはCからのタスクを待機
notを使用してスタックを呼び出すawaitを使用:AがCからタスクを待機し、Bが返しました。
これも私を混乱させ、以前の答えはあなたの実際の質問を見過ごしていたと感じています:
内側のDoAnotherThingAsync()呼び出しから直接Taskを返すことができるのに、return awaitコンストラクトを使用するのはなぜですか?
まあ時々実際Task<SomeType>
が欲しいのですが、ほとんどの場合、実際にはSomeType
のインスタンス、つまりタスクの結果が必要です。
コードから:
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
構文に慣れていない人(たとえば、私)は、このメソッドがTask<SomeResult>
を返すべきだと考えるかもしれませんが、async
でマークされているため、実際の戻り型はSomeResult
であることを意味します。 return foo.DoAnotherThingAsync()
を使用するだけの場合、コンパイルされないTaskを返します。正しい方法は、タスクの結果を返すことです。したがって、return await
です。