この状況こそ、Task
、async
、そしてawait
本当に輝くところです。以下は、同じ例を最大限に活用するためにリファクタリングしたものです(マッピング コードをクリーンアップするために、私のAsyncExasync
ライブラリのヘルパー クラスもいくつか使用しています)。
// First, a base class that takes care of the Task -> IAsyncResult mapping.
// In .NET 4.5, you would use HttpTaskAsyncHandler instead.
public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler
{
public abstract Task ProcessRequestAsync(HttpContext context);
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var task = ProcessRequestAsync(context);
return Nito.AsyncEx.AsyncFactory.ToBegin(task, cb, extraData);
}
void EndProcessRequest(IAsyncResult result)
{
Nito.AsyncEx.AsyncFactory.ToEnd(result);
}
void ProcessRequest(HttpContext context)
{
EndProcessRequest(BeginProcessRequest(context, null, null));
}
public virtual bool IsReusable
{
get { return true; }
}
}
// Now, our (async) Task implementation
public class MyAsyncHandler : HttpAsyncHandlerBase
{
public override async Task ProcessRequestAsync(HttpContext context)
{
using (var webClient = new WebClient())
{
var data = await webClient.DownloadDataTaskAsync("http://my resource");
context.Response.ContentType = "text/xml";
context.Response.OutputStream.Write(data, 0, data.Length);
}
}
}
(コードに示されているように、.NET 4.5 には上記HttpTaskAsyncHandler
と同様の がありますHttpAsyncHandlerBase
)。
素晴らしい点は、バックグラウンド操作の実行中にスレッドを使用しないことです。async
- ASP.NET 要求スレッドが要求を開始し、
WebClient
.
- ダウンロードの進行中、 は
await
実際にメソッドから戻りasync
、リクエスト スレッドを離れます。そのリクエスト スレッドはスレッド プールに戻され、0 (ゼロ) スレッドがこのリクエストにサービスを提供します。
- ダウンロードが完了すると
async
、リクエスト スレッドでメソッドが再開されます。その要求スレッドは、実際の応答を書き込むためだけに簡単に使用されます。
これが最適なスレッド ソリューションです (応答を書き込むには要求スレッドが必要なため)。
元の例でもスレッドが最適に使用されています。スレッドに関する限り、async
ベースのコードと同じです。しかし、IMOasync
コードは読みやすいです。
について詳しく知りたい場合はasync
、私のブログに紹介記事があります。