Acabei de adquirir o VS2012 e tentar entender async
.
Digamos que eu tenho um método que busca algum valor de uma fonte de bloqueio. Não quero que o chamador do método seja bloqueado. Eu poderia escrever o método para receber um retorno de chamada que é chamado quando o valor chega, mas como estou usando o C # 5, decido tornar o método assíncrono para que os chamadores não precisem lidar com retornos de chamada:
// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
return Task.Factory.StartNew(() => {
Console.Write(prompt);
return Console.ReadLine();
});
}
Aqui está um método de exemplo que o chama. Se PromptForStringAsync
não fosse assíncrono, esse método exigiria o aninhamento de um retorno de chamada em um retorno de chamada. Com o async, escrevo meu método dessa maneira muito natural:
public static async Task GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
Console.WriteLine("Welcome {0}.", firstname);
string lastname = await PromptForStringAsync("Enter your last name: ");
Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}
Por enquanto, tudo bem. O problema é quando eu chamo GetNameAsync:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
O ponto principal GetNameAsync
é que é assíncrono. Não quero que ele bloqueie, porque quero voltar para o MainWorkOfApplicationIDontWantBlocked o mais rápido possível e permitir que GetNameAsync faça suas coisas em segundo plano. No entanto, chamar dessa maneira me dá um aviso do compilador na GetNameAsync
linha:
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
Estou perfeitamente ciente de que "a execução do método atual continua antes que a chamada seja concluída". Esse é o objetivo do código assíncrono, certo?
Prefiro que meu código seja compilado sem avisos, mas não há nada para "corrigir" aqui, porque o código está fazendo exatamente o que pretendo fazer. Posso me livrar do aviso armazenando o valor de retorno de GetNameAsync
:
public static void DoStuff()
{
var result = GetNameAsync(); // supress warning
MainWorkOfApplicationIDontWantBlocked();
}
Mas agora eu tenho código supérfluo. O Visual Studio parece entender que fui forçado a escrever esse código desnecessário, porque suprime o aviso "valor nunca usado" normal.
Também posso me livrar do aviso envolvendo GetNameAsync em um método que não é assíncrono:
public static Task GetNameWrapper()
{
return GetNameAsync();
}
Mas esse é um código ainda mais supérfluo. Portanto, tenho que escrever um código que não preciso ou tolero um aviso desnecessário.
Existe algo sobre meu uso de assíncrono errado aqui?
GetNameAsync
fornecer o nome completo que foi fornecida pelo usuário (ou seja Task<Name>
, ao invés de apenas retornar um Task
? DoStuff
Poderia, então, armazenar essa tarefa, e quer await
que após o outro método, ou mesmo passar a tarefa para a outra método para que ele pudesse await
ou Wait
em algum lugar dentro dele de implementação.
async
palavra - chave
PromptForStringAsync
você trabalha mais do que precisa; basta retornar o resultado deTask.Factory.StartNew
. Já é uma tarefa cujo valor é a sequência inserida no console. Não há necessidade de esperar o retorno do resultado; isso não agrega nenhum novo valor.