メソッド内でasync / awaitを使用したくないが、外部からawaitキーワードを使用できるように「装飾」する場合は、TaskCompletionSource.cs:
public static Task<T> RunAsync<T>(Func<T> function)
{
if (function == null) throw new ArgumentNullException(“function”);
var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
T result = function();
tcs.SetResult(result);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
こことここから
タスクでこのようなパラダイムをサポートするには、タスクファサードを保持する方法と、任意の非同期操作をタスクとして参照する機能が必要ですが、そのタスクのライフタイムは、非同期性、そして大幅なコストをかけない方法でそうすること。これがTaskCompletionSourceの目的です。
私が見たものは、.NETソースでも使用されています。WebClient.cs:
[HostProtection(ExternalThreading = true)]
[ComVisible(false)]
public Task<string> UploadStringTaskAsync(Uri address, string method, string data)
{
// Create the task to be returned
var tcs = new TaskCompletionSource<string>(address);
// Setup the callback event handler
UploadStringCompletedEventHandler handler = null;
handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion);
this.UploadStringCompleted += handler;
// Start the async operation.
try { this.UploadStringAsync(address, method, data, tcs); }
catch
{
this.UploadStringCompleted -= handler;
throw;
}
// Return the task that represents the async operation
return tcs.Task;
}
最後に、私は次のことも役に立つと思いました:
私はいつもこの質問をされます。つまり、外部リソースへのI / O呼び出しをブロックしているスレッドがどこかにある必要があります。したがって、非同期コードは要求スレッドを解放しますが、システムの他の場所にある別のスレッドを犠牲にしてのみですよね?いいえ、まったく違います。非同期要求がスケーリングする理由を理解するために、非同期I / O呼び出しの(簡略化された)例をトレースします。リクエストがファイルに書き込む必要があるとしましょう。要求スレッドは非同期書き込みメソッドを呼び出します。WriteAsyncは、基本クラスライブラリ(BCL)によって実装され、非同期I / Oに完了ポートを使用します。したがって、WriteAsync呼び出しは、非同期のファイル書き込みとしてOSに渡されます。次に、OSはドライバースタックと通信し、データを渡してI / O要求パケット(IRP)に書き込みます。これは物事が面白くなるところです:デバイスドライバーがIRPをすぐに処理できない場合は、非同期で処理する必要があります。したがって、ドライバはディスクに書き込みを開始するように指示し、「保留中」の応答をOSに返します。OSはその「保留中」の応答をBCLに渡し、BCLは不完全なタスクを要求処理コードに返します。要求処理コードはタスクを待機し、そのメソッドから不完全なタスクを返します。最後に、要求処理コードはASP.NETに不完全なタスクを返し、要求スレッドは解放されてスレッドプールに戻ります。要求処理コードはタスクを待機し、そのメソッドから不完全なタスクを返します。最後に、要求処理コードはASP.NETに不完全なタスクを返すことになり、要求スレッドは解放されてスレッドプールに戻ります。要求処理コードはタスクを待機し、そのメソッドから不完全なタスクを返します。最後に、要求処理コードはASP.NETに不完全なタスクを返すことになり、要求スレッドは解放されてスレッドプールに戻ります。
ASP.NETでの非同期/待機の概要
ターゲットがスケーラビリティ(応答性ではなく)の向上である場合、それはすべて、それを行う機会を提供する外部I / Oの存在に依存しています。