あるどれかこのような書き方のシナリオ:
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();
}
理にかなっているだろうか?
なぜ使うのかreturn await
直接戻ることができるときに構成するTask<T>
内側からDoAnotherThingAsync()
呼び出し?
私はコードを見ますreturn await
非常に多くの場所で、私は何かを逃したはずだと思います。しかし、私が理解している限りでは、この場合にasync / awaitキーワードを使用せずにタスクを直接返すことは機能的に同等です。追加のオーバーヘッドを追加する理由await
層?
卑劣なケースが1つあります。return
通常の方法ではreturn await
にasync
メソッドの動作が異なります。using
(または、より一般的には、return await
でtry
ブロック)。
メソッドのこれら2つのバージョンを考えます。
Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return foo.DoAnotherThingAsync();
}
}
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
最初の方法はDispose()
のFoo
すぐにオブジェクトDoAnotherThingAsync()
メソッドが戻りますが、実際には完了するまでにかなり時間がかかります。これは最初のバージョンがおそらくバグがあることを意味します(なぜならFoo
2番目のバージョンは正常に動作しますが、間に合わない)。
foo.DoAnotherThingAsync().ContinueWith(_ => foo.Dispose());
- ghordDispose()
戻るvoid
。あなたはのようなものが必要でしょうreturn foo.DoAnotherThingAsync().ContinueWith(t -> { foo.Dispose(); return t.Result; });
。しかし、2番目のオプションを使用できるときに、なぜそうするのかわかりません。 - svick{ var task = DoAnotherThingAsync(); task.ContinueWith(_ => foo.Dispose()); return task; }
。ユースケースは非常に簡単です。あなたが(ほとんどのように)あなたが.NET 4.0を使っているなら、あなたはまだうまく非同期コードを書くことができます。 - ghordFoo
返された後のみTask
不必要に並行性が導入されるため、完了しません。 - svick
必要ない場合async
(つまり、あなたはTask
直接)、その後使用しないでくださいasync
。
いくつかの状況がありますreturn await
あなたが持っているかのように、便利です二行う非同期操作:
var intermediate = await FirstAsync();
return await SecondAwait(intermediate);
詳しくはasync
パフォーマンス、スティーブントゥーブのを参照してくださいMSDNの記事そしてビデオ話題になっている。
更新:私は書いたブログ記事それはもっと詳細に入ります。
await
2番目のケースで便利ですか?しないでくださいreturn SecondAwait(intermediate);
? - Matt Smithreturn SecondAwait(intermediate);
その場合も目標を達成する?おもうreturn await
ここでも冗長です... - TX_await
1行目では、2行目でも使用する必要があります。 - svickasync
バージョンが使用しますもっと少なく同期バージョンよりリソース(スレッド)。 - svickSecondAwait
&quot; CS4016:これは非同期メソッドであるため、戻り式はタイプ&#39; string&#39;である必要があります。 &#39;タスク&lt; string&gt;&#39;&quot;ではなく。 - svick
あなたがそれをしたいと思う唯一の理由は他に何かがあるかどうかですawait
以前のコードで、または何らかの方法で結果を返す前に操作する場合。それが起こっているかもしれないもう一つの方法は、try/catch
それによって、例外の処理方法が変わります。あなたがそれのどれもしていないならそれからあなたは正しい、メソッドを作ることのオーバーヘッドを加える理由はないasync
。
return await
(子呼び出しのタスクを単に返す代わりに)必要である他のコードが以前のコードで待っていたとしても。説明をお願いします。 - TX_async
それでは、どのようにして最初のタスクを待ちますか?メソッドにマークを付ける必要がありますasync
使いたい場合どれか待っています。メソッドがとしてマークされている場合async
そしてあなたはawait
コードの初期の段階ではawait
それが適切なタイプであるための2番目の非同期操作。削除したばかりの場合await
そうすると、戻り値が適切な型にならないため、コンパイルできません。メソッドはasync
結果は常にタスクにラップされています。 - Servyasync
タスクを返さない方法では、タスクの結果が返され、その結果はラップされます。 - ServyTask<Type>
明示的にasync
戻るように指示するType
(コンパイラ自体はTask<Type>
) - noseratioasync
明示的に継続を配線するための単なる構文上の糖です。あなたはしていません必要
async
何かをするためですが、重要な非同期操作を実行するときには、劇的により扱いやすくなります。たとえば、指定したコードでは実際にエラーが発生することはありませんが、さらに複雑な状況で適切に実行すると、かなり困難になります。あなたは二度と必要
async
、私が説明する状況は、それを使用する価値がある場所です。 - Servy
あなたが結果を待つ必要があるかもしれないもう一つのケースはこれです:
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
この場合、GetIFooAsync()
の結果を待たなければならないGetFooAsync
タイプのためT
2つの方法ではTask<Foo>
に直接割り当てることはできませんTask<IFoo>
。しかし、あなたが結果を待つならば、それはちょうどFoo
どっちですに直接割り当て可能IFoo
。それからasyncメソッドは結果を内部に再パッケージ化するだけですTask<IFoo>
そして離れて行きます。
それ以外の点では単純な「さんく」メソッドを非同期にすると、メモリ内に非同期ステートマシンが作成されますが、非同期ではないメソッドは作成されません。非効率的なバージョンの方が効率的であるため(これは本当ですが)、非同期でないバージョンを使用することを人々に指摘することがよくありますが、ハングの場合にはそのメソッドが「return / continuation stack」に関与するという証拠もありません。これは時々ハングを理解するのを難しくします。
つまり、perfが重要ではない(そして通常は重要ではない)場合は、これらすべてのさんくメソッドにasyncをスローして、後でハングしたときの診断に役立つ非同期ステートマシンを使用します。さんくメソッドは時間の経過とともに進化します、彼らはスローの代わりに失敗したタスクを返すようになるでしょう。
これも私を混乱させ、私は以前の答えはあなたの実際の質問を見落としていたと感じます:
内側の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
。
var task = DoSomethingAsync();
あなたにタスクを与えるのではなく、T
- Shoeasync/await
事私の理解では、Task task = DoSomethingAsync()
その間Something something = await DoSomethingAsync()
どちらもうまくいきます。 1つ目はあなたに適切なタスクを与えますが、2つ目はawait
キーワードは、あなたに与える結果完了後のタスクから例えば、Task task = DoSomethingAsync(); Something something = await task;
。 - heltonbiker