Pregunta

He estado siguiendo el nuevo anuncio sobre la nueva característica async que será en C # 5.0. Tengo un conocimiento básico de estilo que pasa a continuación y de la transformación del nuevo compilador de C # hace al código como el siguiente fragmento de de Eric Lippert posterior :

async void ArchiveDocuments(List<Url> urls)
{
  Task archive = null;
  for(int i = 0; i < urls.Count; ++i)
  {
    var document = await FetchAsync(urls[i]);
    if (archive != null)
      await archive;
    archive = ArchiveAsync(document);
  }
}

Sé que algunos lenguajes implementan continuaciones de forma nativa, a través de llamada-con-corriente de continuación (callcc), pero no realmente entender cómo funciona o lo que hace exactamente.

Así que aquí está la pregunta: si Anders et al. había decidido hacer de tripas corazón y acaba de poner en práctica callcc en C # 5.0 en lugar del caso especial async / await, ¿cuál sería el aspecto fragmento anterior como?

¿Fue útil?

Solución

Respuesta original:

Su pregunta, como yo lo entiendo, es "¿y si en lugar de implementar 'se espera la' específicamente para asincronía basada en tareas, más bien, la operación de flujo de control más general de se había aplicado llamada con corriente de continuación?"

Bueno, primero que todos vamos a pensar en lo que "se espera la" hace. "Se espera la" toma una expresión de tipo Task<T>, obtiene un awaiter, y llama a la awaiter con la continuación actual:

await FooAsync()

se convierte efectivamente

var task = FooAsync();
var awaiter = task.GetAwaiter();
awaiter.BeginAwait(somehow get the current continuation);

Ahora supongamos que tenemos un callcc operador que toma como argumento un método, y llama al método con la continuación actual. Que se vería así:

var task = FooAsync();
var awaiter = task.GetAwaiter();
callcc awaiter.BeginAwait;

En otras palabras:

await FooAsync()

no es más que

callcc FooAsync().GetAwaiter().BeginAwait;

¿Responde eso a su pregunta?


Actualización # 1:

Como comentarista señala, la respuesta a continuación supone el patrón de generación de código de la versión "muestra de tecnología" de la función asíncrona / esperan. En realidad, generando el código ligeramente diferente en la versión beta de la función, aunque lógicamente es el mismo. La presente codegen es algo como:

var task = FooAsync();
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
    awaiter.OnCompleted(somehow get the current continuation);
    // control now returns to the caller; when the task is complete control resumes...
}
// ... here:
result = awaiter.GetResult();
// And now the task builder for the current method is updated with the result.

Tenga en cuenta que esto es algo más complicado, y Trata el caso en el que está "a la espera de" un resultado que ya ha sido calculada. No hay necesidad de pasar por todo el galimatías de ceder el control a la persona que llama y recogiendo de nuevo donde lo dejó si el resultado que usted está esperando es, de hecho, ya en caché en la memoria para que allí mismo.

De este modo la conexión entre "lo esperan" y "callcc" no es tan sencillo como lo fue en la versión preliminar, pero todavía es evidente que estamos haciendo esencialmente un callcc en el método "OnCompleted" de la awaiter. Simplemente no hacer lo callcc si no tenemos a.


Actualización # 2:

Como esta respuesta

https://stackoverflow.com/a/9826822/88656

de Timwi señala, la semántica de llamada / cc y esperar no son exactamente lo mismo; una "verdadera" llamada / cc requiere ya sea que la "captura" del toda continuación de un método que incluye la totalidad de su Pila de llamadas , o equivalentemente que todo el programa de reescribirse en la continuación pasando estilo.

La función "esperan ser" es más como una "llamada cooperativa / cc"; la continuación sólo captura "¿Qué es la corriente método tarea de volver a punto de hacer a continuación en el punto de la esperan ser?" Si el persona que llama del método tarea de volver va a hacer algo interesante después de que la tarea se ha completado, entonces es libre de inscribirse su continuación como la continuación de la tarea.

Otros consejos

No soy un experto en continuaciones, pero voy a tomar una puñalada a explicar la diferencia entre asíncrono / El esperan llamada / cc. Por supuesto, esta explicación asume que entiendo llamada / cc y asíncrono / esperan, lo que no estoy seguro de lo que hago. Sin embargo, aquí va ...

Con C # 'asíncrono', le está diciendo al compilador que genere una versión especial de este método específico que entiende la forma de la botella es de Estado en una estructura de lixiviación en los datos, lo que puede ser "retirado de la pila real" y reanudado después. Dentro de un contexto asíncrono, "se espera la" es entonces como "llamada / cc", ya que utiliza los objetos generados por el compilador para reprimir el estado y bajar la "pila real" hasta que se complete la tarea. Sin embargo, debido a que es el compilador de la reescritura de un método asíncrono que permite al estado para ser embotellado, esperan sólo se puede utilizar dentro de un contexto asincrónico.

En la llamada / cc de primera clase, el tiempo de ejecución de lenguaje genera todo el código de tal manera que la continuación de corriente puede ser embotellada en una de continuación de la función de llamada (haciendo que la palabra clave asíncrono innecesario). llamada / cc todavía actúa como esperan, haciendo que el estado actual de continuación (pensar en el estado de pila) que se botled y pasa como una función para la función llamada. Una forma de hacer esto es utilizar montón plazos para todos función de invocación, en lugar de los marcos de pila ''. (A veces conocido como 'sin pérdida de velocidad', como en 'sin apilado Python' o muchas implementaciones del esquema) Otra forma es eliminar todos los datos de la "pila real" y esas cosas en una estructura de datos del montón antes de llamar a la meta de llamada / cc .

Algunos aspectos espinosos puede surgir si hay llamadas a funciones externas (piensa DllImport) entremezclados en la pila. Sospecho que esta es la razón por la que fueron con la aplicación asíncrono / esperan.

http://www.madore.org/~david/computers/callcc. html


Debido a que en C #, una función debe ser marcado como "asíncrono" con el fin de utilizar estas mecánicas, me pregunto si esta palabra clave asíncrono se convertirá en un virus, que se una gran cantidad de funciones en una gran cantidad de bibliotecas. Si esto pasa. que pueden llegar a darse cuenta de que deben poner en práctica la llamada de primera clase / cc a nivel de máquina virtual, en lugar de este compilador-reescritura basada asíncrono modelo. Sólo el tiempo dirá. Sin embargo, es sin duda una herramienta útil en el contexto del entorno actual de C #.

Un poco sentido diría. intérpretes Scheme menudo implementan llamada / cc con una máquina de estados que las capturas de estado local en el montón. Que es exactamente lo que C # 5.0 (o más correctamente C # iterador de 2.0) también lo hace. Ellos hizo implementar llamada / cc, la abstracción se les ocurrió es bastante elegante.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top