2011-12-12 24 views
6

Esta es probablemente una de las cosas más elementales en F #, pero me acabo de dar cuenta de que no tengo idea de lo que sucede detrás de los escenarios.¿Espera sin bloquear el hilo? - ¿Cómo?

let testMe() = 
    async { printfn "before!" 
      do! myAsyncFunction() // Waits without blocking thread 
      printfn "after!" } 

testMe |> Async.RunSynchronously 

¿Qué está pasando en do! myAsyncFunction()? Soy consciente de que espera a que termine myAsyncFunction, antes de continuar. Pero, ¿cómo puede hacer eso, sin bloquear el hilo?

Mi mejor conjetura es que todo lo que después se pasa a lo largo de do! myAsyncFunction() como una continuación, que es ejecutado en el mismo subproceso myAsyncFunction() estaba previsto, una vez que ha finalizado la ejecución myAsyncFunction() .. pero, de nuevo, eso es sólo una conjetura.

+1

Su suposición es correcta, aunque creo que la continuación se llevará a cabo en el siguiente hilo disponible en el grupo de subprocesos, no necesariamente el mismo hilo. – Daniel

Respuesta

5

Como señaló correctamente, se pasa una continuación al myAsyncFunction y lo llama para reanudar el resto del flujo de trabajo asíncrono cuando finaliza.

Puede entenderlo mejor observando la versión Desazucarado del código:

let testMe() = 
    async.Delay(fun() -> 
    printfn "before!" 
    async.Bind(myAsyncFunction(), fun() -> 
     printfn "after!" 
     async.Zero())) 

Ellos clave es que el flujo de trabajo asíncrono creado por myAsyncFunction se le da a la operación Bind que se inicia y se lo da el segundo argumento (una continuación) como una función para llamar cuando se completa el flujo de trabajo. Si simplifica mucho, entonces un flujo de trabajo asíncrono podría definirse así:

type MyAsync<'T> = (('T -> unit) * (exn -> unit)) -> unit 

Por lo tanto, un flujo de trabajo asíncrono es sólo una función que toma algunas continuaciones como argumento. Cuando obtiene las continuaciones, hace algo (es decir, crea un temporizador o inicia la E/S) y luego llama a estas continuaciones. La pregunta "¿En qué hilo se llaman las continuaciones?" es interesante: en un modelo simple, depende del MyAsync que está iniciando; puede decidir ejecutarlos en cualquier lugar que desee (es decir, Async.SwithcToNewThread los ejecuta en un nuevo hilo). La biblioteca F # incluye un manejo adicional que facilita la programación de la GUI utilizando flujos de trabajo.

Su ejemplo utiliza Async.RunImmediate, que bloquea el hilo actual, pero también puede usar Async.Start, que solo inicia el flujo de trabajo e ignora el resultado cuando se produce. La implementación de Async.Start podría tener este aspecto:

let Start (async:MyAsync<unit>) = async (ignore, ignore) 
Cuestiones relacionadas