Eu tenho um async
método que não retorna dados:
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
Estou chamando isso de outro método que retorna alguns dados:
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
Ligar MyAsyncMethod()
sem aguardar causa um aviso " Como essa chamada não é aguardada, o método atual continua a ser executado antes que a chamada seja concluída " no visual studio. Na página desse aviso, ele declara:
Você deve suprimir o aviso apenas se tiver certeza de que não deseja aguardar a conclusão da chamada assíncrona e de que o método chamado não apresentará exceções .
Tenho certeza de que não quero esperar a ligação terminar; Eu não preciso ou tenho tempo para isso. Mas a ligação pode gerar exceções.
Eu me deparei com esse problema algumas vezes e tenho certeza de que é um problema comum que deve ter uma solução comum.
Como chamo com segurança um método assíncrono sem aguardar o resultado?
Atualizar:
Para as pessoas que sugerem que eu apenas espero o resultado, esse é um código que está respondendo a uma solicitação da Web em nosso serviço da Web (API da Web do ASP.NET). Aguardar em um contexto de interface do usuário mantém o encadeamento da interface do usuário livre, mas aguardar em uma chamada de solicitação da Web aguardará a conclusão da tarefa antes de responder à solicitação, aumentando assim os tempos de resposta sem motivo.
fonte
MyAsyncMethod().Wait()
Respostas:
Se você deseja obter a exceção "de forma assíncrona", você pode:
Isso permitirá que você lide com uma exceção em um segmento que não seja o segmento "principal". Isso significa que você não precisa "esperar" a chamada
MyAsyncMethod()
do thread que chamaMyAsyncMethod
; mas ainda permite que você faça algo com uma exceção - mas somente se ocorrer uma exceção.Atualizar:
tecnicamente, você poderia fazer algo semelhante com
await
:... o que seria útil se você precisasse usar especificamente
try
/catch
(ouusing
), mas achoContinueWith
que isso é um pouco mais explícito, porque você precisa saber o queConfigureAwait(false)
significa.fonte
Task
: public static class AsyncUtility {public static void PerformAsyncTaskWithoutAwait (esta tarefa, Action <Task> exceptionHandler) {var dummy = task.ContinueWith (t => exceptionHandler (t), TaskContinuationOptions.OnlyOnFaulted); }} Uso: MyAsyncMethod (). PerformAsyncTaskWithoutAwait (t => log.ErrorFormat ("Ocorreu um erro ao chamar MyAsyncMethod: \ n {0}", t.Exception));ConfiguratAwait(false)
não é executada até que a tarefa seja concluída, mas o segmento atual não "espera" (isto é, bloco) por isso, a próxima linha é chamada de forma assíncrona para a chamada em espera. Sem aConfigureAwait(false)
próxima linha, ela seria executada no contexto original da solicitação da web. Com oConfigurateAwait(false)
ele é executado no mesmo contexto como o método assíncrono (tarefa), liberando o original contexto / thread para continuar ...Você deve primeiro pensar em criar
GetStringData
umasync
método e fazer com queawait
a tarefa seja retornadaMyAsyncMethod
.Se tiver certeza absoluta de que não precisa lidar com exceções
MyAsyncMethod
ou saber quando elas são concluídas, faça o seguinte:BTW, este não é um "problema comum". É muito raro querer executar algum código e não se importar se é concluído ou não, se é concluído com êxito.
Atualizar:
Como você está no ASP.NET e deseja retornar mais cedo, você pode achar útil minha postagem no blog sobre o assunto . No entanto, o ASP.NET não foi projetado para isso e não há garantia de que seu código será executado após o retorno da resposta. O ASP.NET fará o possível para deixá-lo funcionar, mas não pode garantir.
Portanto, esta é uma boa solução para algo simples, como lançar um evento em um log, onde realmente não importa se você perder alguns aqui e ali. Não é uma boa solução para qualquer tipo de operações críticas aos negócios. Nessas situações, você deve adotar uma arquitetura mais complexa, com uma maneira persistente de salvar as operações (por exemplo, Filas do Azure, MSMQ) e um processo em segundo plano separado (por exemplo, Função de Trabalhador do Azure, Serviço Win32) para processá-las.
fonte
var _ = MyAsyncMethod();
por_ = MyAsyncMethod();
. Isso ainda evita o aviso CS4014, mas torna um pouco mais explícito que você não está usando a variável.A resposta de Peter Ritchie era o que eu queria, e o artigo de Stephen Cleary sobre retornar cedo no ASP.NET foi muito útil.
No entanto, como um problema mais geral (não específico ao contexto do ASP.NET), o aplicativo Console a seguir demonstra o uso e o comportamento da resposta de Peter usando
Task.ContinueWith(...)
GetStringData()
retornos início sem aguardarMyAsyncMethod()
e exceções lançadas emMyAsyncMethod()
são tratados nosOnMyAsyncMethodFailed(Task task)
e não natry
/catch
em torno deGetStringData()
fonte
Console.ReadLine();
e adicione um pouco de sono / atrasoMyAsyncMethod
e você nunca verá a exceção.Termino com esta solução:
fonte
Isso é chamado de fogo e esqueça, e há uma extensão para isso.
Instale o pacote nuget .
Usar:
fonte
Acho que surge a pergunta, por que você precisaria fazer isso? O motivo para o
async
C # 5.0 é que você pode aguardar um resultado. Esse método não é realmente assíncrono, mas simplesmente chamado de cada vez, para não interferir muito no encadeamento atual.Talvez seja melhor iniciar um thread e deixá-lo terminar por conta própria.
fonte
async
é um pouco mais do que apenas "aguardar" um resultado. "aguardar" implica que as linhas após "aguardar" sejam executadas de forma assíncrona no mesmo encadeamento que chamou "aguardar". Isso pode ser feito sem "aguardar", é claro, mas você acaba tendo vários delegados e perde a aparência sequencial do código (assim como a capacidade de usarusing
etry/catch
...await
palavra - chave e não aasync
palavra - chave, mas não faz sentido usar aasync
palavra - chave sem usar tambémawait
na definição desse método.async
é um pouco mais do que apenas" aguardar "um resultado". Aasync
palavra-chave (você implícita que é a palavra-chave colocando-a em backticks) significa apenas aguardar o resultado. É assincronia, como os conceitos gerais de CS, que significa mais do que apenas esperar um resultado.async
cria uma máquina de estado que gerencia qualquer espera dentro do método assíncrono. Se não houverawait
s no método, ele ainda criará essa máquina de estado - mas o método não é assíncrono. E se oasync
método retornarvoid
, não há nada a aguardar. Então, é mais do que apenas esperar um resultado.async
palavra - chave. Tudo o que você precisa fazer (e tudo o que realmente acontece no final com uma máquina de estado nesse caso especial) é que o método seja executado de forma síncrona e depois envolvido em uma tarefa concluída. Suponho que tecnicamente você não apenas remova a máquina de estado; você remove a máquina de estado e depois ligaTask.FromResult
. Presumi que você (e também os escritores do compilador) poderia adicionar o adendo por conta própria.Em tecnologias com loops de mensagens (não tenho certeza se o ASP é um deles), você pode bloquear o loop e processar as mensagens até que a tarefa termine e usar o ContinueWith para desbloquear o código:
Essa abordagem é semelhante ao bloqueio no ShowDialog e ainda mantém a interface do usuário responsiva.
fonte
Estou atrasado para a festa aqui, mas há uma biblioteca incrível que estou usando e que não vi mencionada nas outras respostas
https://github.com/brminnick/AsyncAwaitBestPractices
Se você precisar "Disparar e esquecer", chame o método de extensão na tarefa.
Passar a ação onException para a chamada garante que você obtenha o melhor dos dois mundos - sem necessidade de aguardar a execução e diminuir a velocidade de seus usuários, mantendo a capacidade de lidar com a exceção de maneira elegante.
No seu exemplo, você usaria assim:
Também fornece AsyncCommands aguardando a implementação do ICommand, o que é ótimo para minha solução MVVM Xamarin
fonte
A solução é iniciar o HttpClient em outra tarefa de execução sem o contexto de sincronização:
fonte
Se você realmente quer fazer isso. Apenas para abordar "Chamar um método assíncrono em C # sem esperar", você pode executar o método assíncrono dentro de a
Task.Run
. Essa abordagem aguardará até oMyAsyncMethod
término.await
desembrulha de forma assíncrona aResult
tarefa, enquanto o uso de Result seria bloqueado até que a tarefa fosse concluída.fonte
Normalmente, o método assíncrono retorna a classe Task. Se você usar o
Wait()
método ou aResult
propriedade e o código lança uma exceção - o tipo de exceção é agrupadoAggregateException
-, é necessário consultarException.InnerException
para localizar a exceção correta.Mas também é possível usá
.GetAwaiter().GetResult()
-lo - ele também espera a tarefa assíncrona, mas não quebra a exceção.Então, aqui está um pequeno exemplo:
Você também pode querer retornar algum parâmetro da função assíncrona - que pode ser conseguida fornecendo extra
Action<return type>
na função assíncrona, por exemplo:Observe que os métodos assíncronos geralmente têm
ASync
nomes de sufixos, apenas para evitar colisões entre funções de sincronização com o mesmo nome. (Por exemploFileStream.ReadAsync
) - Atualizei os nomes das funções para seguir esta recomendação.fonte