Это ситуация, когда Task
, async
и await
действительно сияют.Вот тот же пример, который был переработан для использования всех преимуществ async
(он также использует некоторые вспомогательные классы из моей библиотеки AsyncEx для очистки кода отображения):
// 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
.Но IMO код async
легче читать.
Если вы хотите узнать больше о async
, у меня есть вступительное сообщение в моем блоге.