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());

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.


É 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)

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.