awaitableオブジェクトの作成
4500 ワード
サーバ側でもクライアント側でも、非同期プログラミングは常に行われています.サーバ側では、パフォーマンスを向上させ、より多くの同時トランザクションをサポートするために、スレッドをブロックすることはできません.クライアントでは,ユーザの操作に常にタイムリーに応答できるようにUIスレッドもブロックできないため,非同期プログラミングが必要な場合が多い.しかし、非同期プログラミングは困難であり、シリアルのビジネスロジックは分散され、コードの隅々に散らばっている.
.Netは,最初のbegin/end-invokeモード(APM)からイベントベースの非同期モード(EAP)まで,非同期プログラミングの難易度を低減しようと試みたが,これらの技術はasyncとawaitが現れるまで論理フローが乱される問題を解決しなかった.最新リリースのwin 8とwp 8では、マイクロソフトがアプリケーションの応答性を強調しているため、asyncとawaitの登場はちょうどその時だ.具体的には、この2つのキーワードをどのように使うか、MSDNなどの資料を参照してください.ここで説明したいのは、非同期呼び出し可能なオブジェクトをどのように構築するかです.もちろん、TaskおよびTaskは、次のような最も一般的なawait可能なオブジェクトです.
コントロールのイベント応答に数秒遅延する場合は、次のようにします.
上記と等価な解決策も簡単に考えられます.
ここで注意しなければなりませんTaskRunモードは単純なパッケージであり,新しいスレッドで非同期コードを実行する必要があるため,効率的なモードではない.次に、新しいスレッドを作成することなく、同じ遅延効果を実現する「非同期」関数を独自に構築します(これにより、応答性を向上させるだけでなく、パフォーマンスを向上させることができますが、これは別の物語です).これは通常、TaskCompletionSourceオブジェクトを使用します.
TaskCompletionsourceは、非同期操作が終了するときに結果(TrySetResult)を設定するためにTaskオブジェクトを構築するためによく使用されます.しかしながら、Taskオブジェクトのみがawait可能であるわけではないが、実際には、GetAwaiter()メソッド(このメソッドが返すオブジェクトがINotifyCompletionインタフェースを実装する)を実装したオブジェクトは、いずれもawatableである.
では、int(Int 32)タイプはawaitできますか?もちろんいいです.intタイプにGetAwaiter()メソッドがあればいいです.
まず、非同期遅延を完了し、INotifyCompletionインタフェースを実装できるDelayAwaitクラスを実装します.
GetAwaiter()メソッド、これは簡単です.拡張メソッドの特性を利用すればいいです.
IsCompleted、
OnCompleted、
GetResultこれらの方法は,我々もこれらの方法を実現しなければならない.簡単に言えば、先に判断します.
IsCompleted,偽であれば呼び出す
OnCompletedメソッドでは、非同期操作が完了したときに必要な後続の操作、すなわちawait後のコードを登録します.この背後にあるメカニズムを明らかにしたいなら、WinRTとawaitを深く探究することをお勧めします.
このように見ると、すべてがawaitableになります.
添付(参考資料):
Async/Await FAQ
.Netは,最初のbegin/end-invokeモード(APM)からイベントベースの非同期モード(EAP)まで,非同期プログラミングの難易度を低減しようと試みたが,これらの技術はasyncとawaitが現れるまで論理フローが乱される問題を解決しなかった.最新リリースのwin 8とwp 8では、マイクロソフトがアプリケーションの応答性を強調しているため、asyncとawaitの登場はちょうどその時だ.具体的には、この2つのキーワードをどのように使うか、MSDNなどの資料を参照してください.ここで説明したいのは、非同期呼び出し可能なオブジェクトをどのように構築するかです.もちろん、TaskおよびTask
private async void ok_Click(object sender, EventArgs e)
{
Console.WriteLine(" , :");
//
int ret = await Task<int>.Run(() => {
int total = 0;
for (int i = 0; i < 1000; i++)
{
total += i;
}
return total;
});
Console.WriteLine(" :{0}",ret);
}
コントロールのイベント応答に数秒遅延する場合は、次のようにします.
private async void ok_Click(object sender, EventArgs e)
{
Console.WriteLine(" , UI ");
await Task.Delay(5000);
Console.WriteLine(" , !");
}
上記と等価な解決策も簡単に考えられます.
private async void ok_Click(object sender, EventArgs e)
{
Console.WriteLine(" , UI ");
await Task.Run( ()=>Thread.Sleep(5000) );
Console.WriteLine(" , !");
}
ここで注意しなければなりませんTaskRunモードは単純なパッケージであり,新しいスレッドで非同期コードを実行する必要があるため,効率的なモードではない.次に、新しいスレッドを作成することなく、同じ遅延効果を実現する「非同期」関数を独自に構築します(これにより、応答性を向上させるだけでなく、パフォーマンスを向上させることができますが、これは別の物語です).これは通常、TaskCompletionSourceオブジェクトを使用します.
private async void ok_Click(object sender, EventArgs e)
{
Console.WriteLine(" , UI ");
await MyDelay(5000);
Console.WriteLine(" , !");
}
public Task MyDelay(int ms)
{
TaskCompletionSource<bool> tcs = null;
System.Threading.Timer timer = new System.Threading.Timer(
(obj) => { //
tcs.TrySetResult(true);
},
tcs,-1,-1
);
tcs = new TaskCompletionSource<bool>(timer);
timer.Change(ms, -1);
return tcs.Task;
}
TaskCompletionsourceは、非同期操作が終了するときに結果(TrySetResult)を設定するためにTaskオブジェクトを構築するためによく使用されます.しかしながら、Taskオブジェクトのみがawait可能であるわけではないが、実際には、GetAwaiter()メソッド(このメソッドが返すオブジェクトがINotifyCompletionインタフェースを実装する)を実装したオブジェクトは、いずれもawatableである.
では、int(Int 32)タイプはawaitできますか?もちろんいいです.intタイプにGetAwaiter()メソッドがあればいいです.
まず、非同期遅延を完了し、INotifyCompletionインタフェースを実装できるDelayAwaitクラスを実装します.
public class DelayAwait : INotifyCompletion
{
private int delay;
private bool finished;
public DelayAwait(int ms)
{
this.delay = ms;
}
public bool IsCompleted
{
get { return finished; }
}
public void OnCompleted(Action continuation)
{
new Timer(
(obj) => {
continuation(); // , await
finished = true;
},
this,
delay, //
-1
);
}
public void GetResult() { }
}
では、intタイプを「有」にします.GetAwaiter()メソッド、これは簡単です.拡張メソッドの特性を利用すればいいです.
public static DelayAwait GetAwaiter(this int ms)
{
return new DelayAwait(ms);
}
okです.これにより、非同期遅延機能を完了できます.private async void ok_Click(object sender, EventArgs e)
{
Console.WriteLine(" , UI ");
await 5000; // int GetAwaiter(), awaitable
Console.WriteLine(" , !");
}
DelayAwaitクラスの実装に注意する必要があります.INotifyCompletionはOnCompletedメソッドを実装する必要があることを規定していますが、実際にawaitをサポートするにはIsCompletedプロパティとGetResultメソッドも提供する必要があります.c#コンパイラはawaitのコードに出会って、背後でこっそり、自動的に1つのステータスマシンを生成して本当に“非同期”を実現して、私達は方法が本当に“中断”されると思ってはいけなくて、これはすべてコンパイラが発揮する魔法にすぎません.コンパイラが自動的に生成するコードで、呼び出されます.IsCompleted、
OnCompleted、
GetResultこれらの方法は,我々もこれらの方法を実現しなければならない.簡単に言えば、先に判断します.
IsCompleted,偽であれば呼び出す
OnCompletedメソッドでは、非同期操作が完了したときに必要な後続の操作、すなわちawait後のコードを登録します.この背後にあるメカニズムを明らかにしたいなら、WinRTとawaitを深く探究することをお勧めします.
このように見ると、すべてがawaitableになります.
添付(参考資料):
Async/Await FAQ