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 switchy una caseetiqueta en cada punto de suspensión. En cada punto de suspensión, la función almacena el valor de la caseetiqueta 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:
- No puede mantener el estado en variables locales entre reinicios.
- No puede suspender el "protothread" de una profundidad de llamada arbitraria. (todos los puntos de suspensión deben estar en el nivel 0)
Hay soluciones para ambos:
- Todas las variables locales deben extraerse al contexto del prototipo (contexto que ya es necesario por el hecho de que el prototipo debe almacenar su próximo punto de reanudación)
- Si siente que realmente necesita llamar a otro protothread desde un protothread, "genere" un niño protothread y suspenda hasta la finalización del niño.
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 asyncy awaitson 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.
public Task<object> AmIACoroutine() {
var tcs = new TaskCompletionSource<object>();
return tcs.Task;
}
Suponiendo que asyncno 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.