Primeiro, vamos esclarecer algumas terminologias: "assíncrono" ( async) significa que ele pode retornar o controle ao thread de chamada antes de iniciar. Em um asyncmétodo, esses pontos de "rendimento" são awaitexpressões.
Isso é muito diferente do termo "assíncrono", pois (mis) usado pela documentação do MSDN por anos para significar "é executado em um thread de segundo plano".
Confundir ainda mais a questão, asyncé muito diferente de "aguardável"; existem alguns asyncmétodos cujos tipos de retorno não são aguardáveis e muitos métodos que retornam tipos que não são aguardáveis async.
O suficiente sobre o que eles não são ; aqui estão o que são :
- A
asyncpalavra-chave permite um método assíncrono (ou seja, permite awaitexpressões). asyncmétodos podem retornar Task, Task<T>ou (se for necessário) void.
- Qualquer tipo que segue um determinado padrão pode ser aguardado. Os tipos aguardáveis mais comuns são
Taske Task<T>.
Portanto, se reformularmos sua pergunta para "como posso executar uma operação em um encadeamento em segundo plano de uma maneira que seja aguardável", a resposta é usar Task.Run:
private Task<int> DoWorkAsync() // No async because the method does not need await
{
return Task.Run(() =>
{
return 1 + 2;
});
}
(Mas esse padrão é uma abordagem ruim; veja abaixo).
Mas se sua pergunta é "como criar um asyncmétodo que pode retornar ao chamador em vez de bloquear", a resposta é declarar o método asynce usá-lo awaitpara seus pontos de "retorno":
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.example.com/");
return html.Length;
}
Portanto, o padrão básico das coisas é fazer com que o asynccódigo dependa de "aguardáveis" em suas awaitexpressões. Esses "aguardáveis" podem ser outros asyncmétodos ou apenas métodos regulares que retornam aguardáveis. Métodos regulares retornando Task/ Task<T> pode usar Task.Runpara executar código em um segmento de segundo plano, ou (mais comumente) eles podem usar TaskCompletionSource<T>ou um de seus atalhos ( TaskFactory.FromAsync, Task.FromResult, etc). Eu não recomendo envolvendo um método inteiro em Task.Run; Os métodos síncronos devem ter assinaturas síncronas e deve ser deixado ao consumidor se ele deve ser agrupado em Task.Run:
private int DoWork()
{
return 1 + 2;
}
private void MoreSynchronousProcessing()
{
// Execute it directly (synchronously), since we are also a synchronous method.
var result = DoWork();
...
}
private async Task DoVariousThingsFromTheUIThreadAsync()
{
// I have a bunch of async work to do, and I am executed on the UI thread.
var result = await Task.Run(() => DoWork());
...
}
Eu tenho um async/ awaitintrodução no meu blog; no final, existem alguns bons recursos de acompanhamento. Os documentos do MSDN também asyncsão extraordinariamente bons.