Acabo de empezar a jugar con async / await en .Net 4.5. Una cosa que tengo curiosidad inicialmente es: ¿por qué es necesaria la palabra clave asíncrona? La explicación que leí fue que es un marcador, por lo que el compilador sabe que un método espera algo. Pero parece que el compilador debería poder resolver esto sin una palabra clave. Entonces, ¿qué más hace?
19
Respuestas:
Aquí hay varias respuestas, y todas hablan de lo que hacen los métodos asíncronos, pero ninguna de ellas responde a la pregunta, por eso
async
se necesita como una palabra clave que figura en la declaración de la función.No es "dirigir al compilador para transformar la función de una manera especial";
await
solo podría hacer eso. ¿Por qué? Debido a que C # ya tiene otro mecanismo en el que la presencia de una palabra clave especial en el cuerpo del método hace que el compilador para realizar extrema (y muy similar aasync/await
) transformaciones en el cuerpo del método:yield
.Excepto que
yield
no es su propia palabra clave en C #, y entender por qué se explicaráasync
también. A diferencia de la mayoría de los lenguajes que admiten este mecanismo, en C # no se puedeyield value;
deciryield return value;
. ¿Por qué? Debido a que se agregó al lenguaje después de que C # ya existía, y era bastante razonable suponer que alguien, en algún lugar, podría haber usadoyield
el nombre de una variable. Pero debido a que no existía un escenario preexistente en el que<variable name> return
fuera sintácticamente correcto,yield return
se agregó al lenguaje para que sea posible introducir generadores mientras se mantiene la compatibilidad con el código existente al 100%.Y es por eso que
async
se agregó como un modificador de función: para evitar romper el código existente que se usabaawait
como nombre de variable. Comoasync
ya no existían métodos, no se invalida ningún código antiguo, y en el nuevo código, el compilador puede usar la presencia de laasync
etiqueta para saber queawait
debe tratarse como una palabra clave y no como un identificador.fuente
async
palabra clave se puede eliminar? Obviamente, sería una ruptura de BC, pero podría pensarse que afecta a muy pocos proyectos y es un requisito directo para actualizar (es decir, cambiar el nombre de una variable).cambia el método de un método normal a un objeto con devolución de llamada que requiere un enfoque totalmente diferente para la generación de código
y cuando sucede algo drástico como eso, es costumbre indicarlo claramente (aprendimos esa lección de C ++)
fuente
async
s al mismo tiempo por lo que no se ejecutan, uno tras otro, pero al mismo tiempo (si las roscas están disponibles por lo menos)Task<T>
tienen las características de unasync
método; por ejemplo, puede ejecutar una lógica comercial / de fábrica y luego delegar en algún otro método de devoluciónTask<T>
.async
los métodos tienen un tipo de retornoTask<T>
en la firma pero en realidad no devuelven aTask<T>
, solo devuelven aT
. Para resolver todo esto sin laasync
palabra clave, el compilador de C # tendría que hacer todo tipo de inspección profunda del método, lo que probablemente lo ralentizaría un poco y generaría toda clase de ambigüedades.La idea general con palabras clave como "asíncrono" o "inseguro" es eliminar la ambigüedad en cuanto a cómo se debe tratar el código que modifican. En el caso de la palabra clave asíncrona, le dice al compilador que trate el método modificado como algo que no necesita regresar de inmediato. Esto permite que el hilo donde se usa este método continúe sin tener que esperar los resultados de ese método. Es efectivamente una optimización de código.
fuente
OK, aquí está mi opinión al respecto.
Hay algo llamado corutinas que se conoce desde hace décadas. ("Knuth and Hopper" -clase "durante décadas") Son generalizaciones de subrutinas , en las que no solo obtienen y liberan el control en el inicio de la función y la declaración de retorno, sino que también lo hacen en puntos específicos ( puntos de suspensión ). Una subrutina es una rutina sin puntos de suspensión.
Son FÁCILMENTE FÁCILES de implementar con macros C, como se muestra en el siguiente documento sobre "protothreads". ( http://dunkels.com/adam/dunkels06protothreads.pdf ) Léalo. Esperaré...
La conclusión de esto es que las macros crean una gran
switch
y unacase
etiqueta en cada punto de suspensión. En cada punto de suspensión, la función almacena el valor de lacase
etiqueta que sigue inmediatamente , para que sepa dónde reanudar la ejecución la próxima vez que se llame. Y devuelve el control a la persona que llama.Esto se hace sin modificar el flujo aparente de control del código descrito en el "protothread".
Imagínese ahora que tiene un gran bucle que llama a todos estos "protothreads" a su vez, y obtiene simultáneamente "protothreads" en un solo hilo.
Este enfoque tiene dos inconvenientes:
Hay soluciones para ambos:
Y si tuviera el soporte del compilador para hacer el trabajo de reescritura que hacen las macros y la solución alternativa, bien, podría escribir su código de protothread tal como lo desea e insertar puntos de suspensión con una palabra clave.
Y esto es lo que
async
yawait
son todos acerca de: crear (sin pérdida de velocidad) corrutinas.Las corutinas en C # se reifican como objetos de clase (genérica o no genérica)
Task
.Encuentro estas palabras clave muy engañosas. Mi lectura mental es:
async
como "suspensible"await
como "suspender hasta la finalización de"Task
como "futuro ..."Ahora. ¿Realmente necesitamos marcar la función
async
? Además de decir que debería activar los mecanismos de reescritura de código para hacer que la función sea una rutina, resuelve algunas ambigüedades. Considera este código.Suponiendo que
async
no sea obligatorio, ¿es esto una función de rutina o normal? ¿Debería el compilador reescribirlo como una rutina o no? Ambos podrían ser posibles con diferentes semánticas eventuales.fuente