2009-01-30 6 views
8

Digamos que quería robar una página web y extraer algunos datos. Yo más probable es que escribiría algo como esto:Mejores prácticas para paralelizar el uso del flujo de trabajo asincrónico

let getAllHyperlinks(url:string) = 
    async { let req = WebRequest.Create(url) 
      let! rsp = req.GetResponseAsync() 
      use stream = rsp.GetResponseStream()    // depends on rsp 
      use reader = new System.IO.StreamReader(stream) // depends on stream 
      let! data = reader.AsyncReadToEnd()    // depends on reader 
      return extractAllUrls(data) }     // depends on data 

El let! dice F # para ejecutar el código en otro hilo, a continuación, enlazar el resultado a una variable, y seguir procesando. El ejemplo anterior utiliza dos instrucciones de let: una para obtener la respuesta y otra para leer todos los datos, por lo que genera al menos dos hilos (corrígeme si me equivoco).

Aunque el flujo de trabajo anterior genera varios subprocesos, el orden de ejecución es serial porque cada elemento en el flujo de trabajo depende del elemento anterior. No es posible evaluar ningún elemento más adelante en el flujo de trabajo hasta que regresen los otros hilos.

¿Hay alguna ventaja de tener más de un let! en el código anterior?

En caso negativo, ¿cómo debería cambiar este código para aprovechar las múltiples declaraciones let!?

Respuesta

9

La clave es que somos no generando nuevos hilos. Durante todo el curso del flujo de trabajo, se consumen 1 o 0 subprocesos activos desde ThreadPool. (Una excepción, hasta el primer '!', El código se ejecuta en el subproceso del usuario que hizo una Async.Run.) "Let!" suelta un hilo mientras la operación Async está en el mar, y luego recoge un hilo del ThreadPool cuando la operación retorna. La ventaja (de rendimiento) es una menor presión contra ThreadPool (y, por supuesto, la principal ventaja para el usuario es el modelo de programación simple, un millón de veces mejor que todas las cosas de BeginFoo/EndFoo/devolución de llamada que de otra forma escribirías).

Ver también http://cs.hubfs.net/forums/thread/8262.aspx

+0

Ok, así que vamos! no engendra múltiples hilos, simplemente libera el manejador del hilo de nuevo a la lista de hilos :) Imagino que esto viene con una pequeña cantidad de sobrecarga, ¡así que probablemente no lo "deje"! todas y cada una de las líneas ¿Hay alguna regla para colocar "let!" en los lugares más óptimos? – Juliet

+0

Place let! en cada línea donde va a hacer una llamada asíncrona que llevará un tiempo y no necesita un hilo mientras está fuera (lectura de la red o secuencia de archivos). Entonces ambos "let!" En tu ejemplo son "buenos". – Brian

+0

Si va a ejecutar muchas copias del flujo de trabajo, cualquier "sobrecarga" de "¡let!" será eclipsado por el retorno que obtiene de mantener la CPU activa sin tener que generar hilos adicionales. – Brian

3

estaba escribiendo una respuesta, pero Brian se me adelantó. Estoy totalmente de acuerdo con él.

Me gustaría agregar que si desea paralelizar el código sincrónico, la herramienta correcta es PLINQ, no flujos de trabajo asincrónicos, como Don Syme explains.

Cuestiones relacionadas