Mejores prácticas con C #. ¿Está bien pasar parámetros con esperar?

8

¿Está bien pasar parámetros, con await? ¿Cuáles son las ventajas y desventajas de hacer esto?

var results = MapResults(await GetDataAsync());
Drew Aguirre
fuente
2
Eso está bien. Todo lo que está haciendo es resolver la Tarea antes de pasar el parámetro. Es exactamente lo mismo que var x = await GetDataAsync; resultados var = MapResults (x); No hay diferencia, y generalmente se reduce a las pautas de codificación que desea implementar para usted mismo
Heinrich
1
Legibilidad de código. Eso es literalmente lo mismo quevar result = await GetDataAsync(); var map = MapResults(result)
Zer0
@ Zer0, ¿cuál es legible, el que tiene resultados var? o la sola línea?
Drew Aguirre
@Heinrich sí, estoy de acuerdo contigo. Solo me preocupa que esté aplicando alguna mala práctica en mi código para hacer una sola línea.
Drew Aguirre
3
@DrewAguirre: esos dos últimos son completamente diferentes y NO DEBES HACER LO ÚLTIMO . Espero que haya quedado claro. El primero hace una espera asincrónica; este último hace una espera síncrona en un flujo de trabajo asíncrono. Ahora, suponga que el flujo de trabajo asincrónico ha programado el trabajo en el futuro en el hilo actual . Una espera sincrónica significa "dormir este hilo hasta que el trabajo que este hilo hará en el futuro esté hecho", y obviamente eso duerme para siempre.
Eric Lippert

Respuestas:

28

ACTUALIZACIÓN: Esta pregunta fue el tema de mi blog en marzo de 2020 . Véalo para más discusión sobre este tema. Gracias por la interesante pregunta!


Asumiré aquí que pretendías que fuera una llamada a la función como único miembro de la lista de argumentos.

Como otros han señalado, no hay diferencia entre

x = M(await FAsync());

y

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

Y eso es lo mismo que

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

Entonces, no importa de qué manera lo escribas, ¿correcto?

Piensa en eso.


En ese escenario específico, los tres flujos de trabajo son iguales. Pero hay una diferencia potencial aquí si solo variamos ligeramente el escenario. Considerar:

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

Esto es lo mismo que

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

¿Y qué sabemos sobre este flujo de trabajo? ¡La tarea GAsync no se inicia hasta que finaliza la tarea FAsync! ¡Pero parece que hay una oportunidad para tener dos tareas al mismo tiempo aquí, lo que podría usar el hilo actual de manera más eficiente! Probablemente el flujo de trabajo se escribiría mejor como:

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

Ahora se inician las tareas FAsync y GAsync, y no llamamos a M hasta que ambas finalicen.

Mi consejo es que piense detenidamente dónde pone su espera. Recuerde, una espera está destinada a ser un punto en un flujo de trabajo asíncrono donde el flujo de trabajo se detiene de forma asíncrona hasta que se cumpla una condición previa de la continuación . Si puede retrasar la espera de una tarea hasta que sea realmente una condición previa, es posible que pueda obtener una victoria por rendimiento.

Eric Lippert
fuente
Por supuesto, es bueno tener en cuenta el soporte subyacente de subprocesos múltiples de las tareas que está esperando. No puede esperar simultáneamente en dos tareas que producen datos de la base de datos y usan la misma SqlConnectiono, DbContextpor ejemplo.
Sebazzz
1
¡Guauu! Estoy impresionado ... lo siento, he estado ocupado y no he respondido a su respuesta ... Marqué esta como la respuesta ... la explicación es muy clara ... y sí, aprendí mucho solo leyendo las pocas líneas que escribió ... y también he leído tu blog ... ¡buen trabajo! y sigan así ..
Drew Aguirre
5

No hay diferencia de tiempo de ejecución entre;

var results = MapResults(await GetDataAsync())

y

var tmp = await GetDataAsync();
var results = MapResults(tmp)
Jeremy Lakeman
fuente
Sí, no hay diferencia. Lo que estoy pensando, ¿hay algún problema técnico para hacer esto? o es más limpio usar la variable "tmp"? No puedo ver ninguna desventaja para usar la primera línea. incluso hay una excepción que arrojará a GetDataAsync ().
Drew Aguirre
¿Es una mala práctica hacer la primera línea?
Drew Aguirre
Prefiero el segundo patrón, 1) más legible, 2) puedo masajear el código antes de pasar a los resultados.
Harris Yer
Tenga en cuenta que OP utilizó la variable ( GetDataAsync) y no la llamada al método. Dependiendo de dónde Task GetDataAsync = CallSomeAsync()se inicialice, podría haber diferencias significativas ya que la tarea ya se estará ejecutando para cuando MapResults(await GetDataAsync)se llame. Vea la respuesta de Eric para más detalles.
Alexei Levenkov
Sí, como no había suficiente contexto, supuse que era un error tipográfico ...
Jeremy Lakeman