Primeiro, vamos esclarecer algumas terminologias: "assíncrono" ( async
) significa que ele pode retornar o controle ao thread de chamada antes de iniciar. Em um async
método, esses pontos de "rendimento" são await
expressõ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 async
mé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
async
palavra-chave permite um método assíncrono (ou seja, permite await
expressões). async
mé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
Task
e 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 async
método que pode retornar ao chamador em vez de bloquear", a resposta é declarar o método async
e usá-lo await
para 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 async
código dependa de "aguardáveis" em suas await
expressões. Esses "aguardáveis" podem ser outros async
métodos ou apenas métodos regulares que retornam aguardáveis. Métodos regulares retornando Task
/ Task<T>
pode usar Task.Run
para 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
/ await
introdução no meu blog; no final, existem alguns bons recursos de acompanhamento. Os documentos do MSDN também async
são extraordinariamente bons.