非同期 CTP を使用せずに await を実装する方法
-
28-10-2019 - |
質問
非同期 CTP と同様に機能するものを実装するにはどうすればよいですか? await
キーワード?次のように動作する簡単な実装はありますか await
すべての場合において、またはそうします await
シナリオごとに異なる実装が必要ですか?
解決
await
常に同じ種類の変化が伴いますが、それはかなり痛みを伴うものです。の 図書館 側面 await
それほど複雑ではありませんが、注意が必要なのは、コンパイラがステート マシンを構築し、継続が正しい場所にジャンプできるようにすることです。
その 可能 私の反復子ブロックのハックな使い方 (yield return) を使えば、同様のものを偽造できるでしょう...しかし、それはかなり醜いでしょう。
私は 数週間前にコンパイラーが舞台裏で何をしているのかについての DevExpress ウェビナー - いくつかの例から逆コンパイルされたコードを示し、コンパイラーが返すタスクをどのように構築するか、および「待機者」が何をしなければならないかを説明します。役に立つかもしれません。
他のヒント
新しいawait
キーワードは、既存のyield return
キーワードと同様のセマンティクスを持ち、どちらもコンパイラーに継続スタイルのステートマシンを生成させます。したがって、非同期CTPと同じ動作をするイテレータを使用して何かを一緒にハッキングすることが可能です。
次のようになります。 ジェネラコディセタグプレ
yield return
はIEnumerable
を生成するため、コルーチンはIEnumerable
を返す必要があります。すべての魔法は、AsyncHelper.Invoke
メソッド内で発生します。これが、コルーチン(ハッキングされたイテレータになりすます)を実行するためのものです。イテレータが存在する場合は、常に現在の同期コンテキストで実行されるように特別な注意が必要です。これは、await
がUIスレッドでどのように機能するかをシミュレートするときに重要です。これを行うには、最初のMoveNext
を同期的に実行し、次にSynchronizationContext.Send
を使用して、個々のステップを非同期的に待機するためにも使用されるワーカースレッドから残りを実行します。
ジェネラコディセタグプレ
TaskCompletionSource
のすべては、await
が値を「返す」方法を複製する試みでした。問題は、コルーチンはハッキングされたイテレータにすぎないため、実際にIEnumerable
を返す必要があることです。 そのため、戻り値を取得するための代替メカニズムを考え出す必要がありました。
これにはいくつかの明白な制限がありますが、これがあなたに一般的な考えを与えることを願っています。また、CLRがコルーチンを実装するための1つの一般化されたメカニズムをどのように持つことができるかを示しています。このメカニズムでは、await
とyield return
がユビキタスに使用されますが、それぞれのセマンティクスを提供する方法は異なります。
イテレータ(yield)で作成されたコルーチンの実装と例はほとんどありません。
例の1つは、非同期GUI操作にこのパターンを使用するCaliburn.Microフレームワークです。ただし、一般的な非同期コードに簡単に一般化できます。
の マインドタッチドリーム フレームワークは、Async/Await と機能的によく似た Iterator パターンの上にコルーチンを実装します。
async Task Foo() {
await SomeAsyncCall();
}
対
IYield Result Foo() {
yield return SomeAsyncCall();
}
Result
DReAMのバージョンです Task
. 。フレームワーク DLL は .NET 2.0 以降で動作しますが、最近は 3.5 構文を多く使用しているため、これを構築するには 3.5 が必要です。
MicrosoftのBillWagnerは、 MSDNMagazineの記事にその方法について書いています。Visual Studio 2010のタスク並列ライブラリを使用して、非同期ctpへの依存関係を追加せずに非同期のような動作を実装できます。
Task
とTask<T>
を幅広く使用します。これには、C#5がリリースされると、コードがasync
とawait
の使用を開始する準備が整うという追加の利点もあります。
私の読書から、yield return
とawait
の主な違いは、await
が継続に新しい値を明示的に返すことができるということです。
ジェネラコディセタグプレ
yield return
では、参照によって同じことを達成する必要があります。
ジェネラコディセタグプレ