Prática recomendada com C #. É bom passar parâmetros com aguardar?

8

É bom passar parâmetros com await? quais são os prós e os contras de fazer isso?

var results = MapResults(await GetDataAsync());
Drew Aguirre
fonte
2
Tudo bem. Tudo o que você está fazendo é resolver a tarefa antes de passar o parâmetro. É exatamente o mesmo que var x = aguardar GetDataAsync; var results = MapResults (x); Não faz diferença, e geralmente se resume às diretrizes de codificação que você deseja implementar por si mesmo
Heinrich
1
Legibilidade do código. É literalmente a mesma coisa quevar result = await GetDataAsync(); var map = MapResults(result)
Zer0
@ Zer0 qual é legível, aquele com resultados var? ou a única linha?
Drew Aguirre
@ Heinrich sim, eu concordo com você. Só me preocupo em aplicar algumas práticas ruins no meu código para fazer uma única linha.
Drew Aguirre
3
@DrewAguirre: esses dois últimos são completamente diferentes e VOCÊ NÃO DEVE FAZER O MAIS TARDE . Espero que esteja claro. O primeiro faz uma espera assíncrona; o último faz uma espera síncrona em um fluxo de trabalho assíncrono. Agora, suponha que o fluxo de trabalho assíncrono tenha agendado trabalho no futuro no encadeamento atual . Uma espera síncrona significa "suspender esse encadeamento até que o trabalho que esse encadeamento realizará no futuro seja concluído" e, obviamente, que durma para sempre.
Eric Lippert

Respostas:

28

ATUALIZAÇÃO: Esta questão foi o assunto do meu blog em março de 2020 . Veja-o para mais discussões sobre esta questão. Obrigado pela pergunta interessante!


Vou assumir aqui que você pretendia que fosse uma chamada de função como o único membro da lista de argumentos.

Como outros observaram, não há diferença entre

x = M(await FAsync());

e

var f = await FAsync();
x = M(f);

E isso é o mesmo que

var ftask = FAsync();
x = M(await ftask)

Portanto, não importa como você escreve, correto?

Pense nisso.


Nesse cenário específico , todos os três fluxos de trabalho são iguais. Mas há uma diferença potencial aqui se apenas variarmos ligeiramente o cenário. Considerar:

x = M(await FAsync(), await GAsync());

É o mesmo que

var f = await FAsync();
var g = await GAsync();
x = M(f, g);

e o que sabemos sobre esse fluxo de trabalho? A tarefa do GAsync não é iniciada até que a tarefa do FAsync seja concluída! Mas parece que há uma oportunidade de ter duas tarefas acontecendo ao mesmo tempo aqui, que podem usar o encadeamento atual com mais eficiência! Provavelmente, o fluxo de trabalho seria melhor escrito como:

var ftask = FAsync();
var gtask = GAsync();
x = M(await ftask, await gtask);

Agora, as tarefas FAsync e GAsync são iniciadas e não chamamos M até que ambas terminem.

Meu conselho é pensar cuidadosamente sobre onde você espera. Lembre-se de que uma espera é um ponto em um fluxo de trabalho assíncrono em que o fluxo de trabalho é interrompido de forma assíncrona até que uma condição prévia da continuação seja atendida . Se você pode adiar a espera de uma tarefa até que ela seja realmente uma pré-condição, poderá conseguir uma vitória no desempenho.

Eric Lippert
fonte
É claro que é bom estar ciente do suporte multithreading subjacente das tarefas que você está aguardando. Você não pode aguardar simultaneamente em duas tarefas que geram dados do banco de dados e usam o mesmo SqlConnectionou DbContextpor exemplo.
Sebazzz 10/03
1
Uau! Estou impressionado .. desculpe, estive ocupado e não respondi na sua resposta .. Marquei esta como a resposta .. a explicação é muito clara .. e sim, aprendi muito apenas lendo as poucas linhas que você escreveu .. e eu também li o seu blog .. bom trabalho! e continue assim ..
Drew Aguirre
5

Não há diferença de tempo de execução entre;

var results = MapResults(await GetDataAsync())

e

var tmp = await GetDataAsync();
var results = MapResults(tmp)
Jeremy Lakeman
fonte
Sim, não há diferença. o que estou pensando, há algum problema técnico para fazer isso? ou é mais limpo usar a variável "tmp"? Não vejo nenhuma desvantagem em usar a primeira linha. mesmo que haja uma exceção que será lançada em GetDataAsync ().
Drew Aguirre
É uma prática ruim fazer a primeira linha?
Drew Aguirre
Prefiro o segundo padrão, 1) mais legível, 2) posso massagear o código antes de passar para os resultados.
Harris Yer
Observe que o OP usou a variável ( GetDataAsync) e não a chamada de método. Dependendo de onde isso Task GetDataAsync = CallSomeAsync()foi inicializado, pode haver diferenças significativas, pois a tarefa já estará em execução quando o tempo MapResults(await GetDataAsync)for chamado. Veja a resposta de Eric para mais detalhes.
Alexei Levenkov
Sim, já que não havia contexto suficiente, presumi que fosse um erro de digitação ...
Jeremy Lakeman