Eu tenho um método no aplicativo ASP.NET, que consome muito tempo para ser concluído. Uma chamada para esse método pode ocorrer até 3 vezes durante uma solicitação do usuário, dependendo do estado do cache e dos parâmetros fornecidos pelo usuário. Cada chamada leva cerca de 1 a 2 segundos para ser concluída. O método em si é uma chamada síncrona para o serviço e não há possibilidade de substituir a implementação.
Portanto, a chamada síncrona para o serviço é semelhante a esta:
public OutputModel Calculate(InputModel input)
{
// do some stuff
return Service.LongRunningCall(input);
}
E o uso do método é (observe que a chamada do método pode acontecer mais de uma vez):
private void MakeRequest()
{
// a lot of other stuff: preparing requests, sending/processing other requests, etc.
var myOutput = Calculate(myInput);
// stuff again
}
Tentei mudar a implementação do meu lado para fornecer um trabalho simultâneo desse método, e aqui está o que eu vim até agora.
public async Task<OutputModel> CalculateAsync(InputModel input)
{
return await Task.Run(() =>
{
return Calculate(input);
});
}
Uso (parte do código "fazer outras coisas" é executado simultaneamente com a chamada para o serviço):
private async Task MakeRequest()
{
// do some stuff
var task = CalculateAsync(myInput);
// do other stuff
var myOutput = await task;
// some more stuff
}
Minha pergunta é a seguinte. Devo usar a abordagem certa para acelerar a execução no aplicativo ASP.NET ou estou fazendo um trabalho desnecessário tentando executar o código síncrono de forma assíncrona? Alguém pode explicar por que a segunda abordagem não é uma opção no ASP.NET (se realmente não for)? Além disso, se essa abordagem for aplicável, preciso chamar esse método de forma assíncrona se for a única chamada que podemos realizar no momento (eu tenho esse caso, quando não há outra coisa a fazer enquanto aguardamos a conclusão)?
A maioria dos artigos na rede sobre esse assunto aborda o uso de async-await
abordagem com o código, que já fornece awaitable
métodos, mas não é o meu caso. Aquié o bom artigo que descreve meu caso, que não descreve a situação de chamadas paralelas, recusando a opção de encerrar a chamada de sincronização, mas na minha opinião minha situação é exatamente a ocasião para fazê-lo.
Agradecemos antecipadamente por ajuda e dicas.
fonte
Task.Run
, o conteúdo é executado em outro thread, que é obtido do pool de threads. Então, não há necessidade de envolver chamadas de bloqueio (como a minha chamada para serviço) emRun
s, porque elas sempre consumirão um thread cada, que será bloqueado durante a execução do método. Em tal situação, o único benefício que restaasync-await
no meu caso é realizar várias ações ao mesmo tempo. Por favor me corrija se eu estiver errado.Run
(ouParallel
) é a simultaneidade. As operações ainda estão bloqueando um thread. Como você diz que o serviço é um serviço da Web, não recomendo usarRun
ouParallel
; em vez disso, escreva uma API assíncrona para o serviço.BeginGetResponse
e iniciar várias delas e, em seguida, bloquear (de forma síncrona) até que todas estejam concluídas, mas esse tipo de abordagem é complicado - consulte blog.stephencleary.com/2012/07/dont-block-on -async-code.html e msdn.microsoft.com/en-us/magazine/mt238404.aspx . Normalmente, é mais fácil e limpo adotarasync
totalmente, se possível.Eu descobri que o código a seguir pode converter uma tarefa para sempre ser executada de forma assíncrona
e eu usei da seguinte maneira
Isso executará qualquer tarefa de forma assíncrona para que você possa combiná-los em cenários WhenAll, WhenAny e outros usos.
Você também pode simplesmente adicionar Task.Yield () como a primeira linha do código chamado.
fonte