Buscar..


Parámetros

Tipo / Función Detalle
data Eval a Eval es una mónada que facilita la definición de estrategias paralelas.
type Strategy a = a -> Eval a Una función que encarna una estrategia de evaluación paralela. La función atraviesa (parte de) su argumento, evaluando subexpresiones en paralelo o en secuencia
rpar :: Strategy a Chispea su argumento (para su evaluación en paralelo)
rseq :: Strategy a Evalúa su argumento a la forma normal de cabeza débil.
force :: NFData a => a -> a evalúa toda la estructura de su argumento, reduciéndolo a su forma normal, antes de devolver el argumento en sí. Es proporcionado por el módulo Control.DeepSeq

Observaciones

El libro de Simon Marlow , Programación concurrente y paralela en Haskell, es sobresaliente y abarca una multitud de conceptos. También es muy accesible incluso para el programador de Haskell más nuevo. Es altamente recomendable y está disponible en PDF o en línea de forma gratuita.

Paralelo vs Concurrente

Simon Marlow lo pone mejor :

Un programa paralelo es uno que utiliza una multiplicidad de hardware computacional (por ejemplo, varios núcleos de procesador) para realizar un cálculo más rápidamente. El objetivo es llegar a la respuesta anterior, delegando diferentes partes de la computación a diferentes procesadores que se ejecutan al mismo tiempo.

Por el contrario, la concurrencia es una técnica de estructuración de programas en la que hay múltiples hilos de control. Conceptualmente, los hilos de control se ejecutan “al mismo tiempo”; Es decir, el usuario ve sus efectos intercalados. Si realmente se ejecutan al mismo tiempo o no es un detalle de implementación; un programa concurrente puede ejecutarse en un solo procesador a través de la ejecución intercalada o en múltiples procesadores físicos.

Forma normal de la cabeza débil

Es importante ser consciente de cómo funciona la evaluación perezosa. La primera sección de este capítulo brindará una sólida introducción a WHNF y cómo esto se relaciona con la programación paralela y concurrente.

La Mónada Eval

El paralelismo en Haskell se puede expresar usando la Mónada Eval de Control.Parallel.Strategies , usando las funciones rpar y rseq (entre otras).

f1 :: [Int]
f1 = [1..100000000]

f2 :: [Int]
f2 = [1..200000000]

main = runEval $ do
  a <- rpar (f1) -- this'll take a while...
  b <- rpar (f2) -- this'll take a while and then some...
  return (a,b)

Ejecutar main anterior ejecutará y "regresará" inmediatamente, mientras que los dos valores, a y b se computan en segundo plano a través de rpar .

Nota: asegúrese de compilar con -threaded para que se produzca la ejecución paralela.

rpar

rpar :: Strategy a ejecuta la estrategia dada (recuerda: type Strategy a = a -> Eval a ) en paralelo:

import Control.Concurrent
import Control.DeepSeq
import Control.Parallel.Strategies
import Data.List.Ordered

main = loop
  where 
    loop = do
      putStrLn "Enter a number"
      n <- getLine

      let lim = read n :: Int
          hf  = quot lim 2
          result = runEval $ do
            -- we split the computation in half, so we can concurrently calculate primes
            as <- rpar (force (primesBtwn 2 hf))
            bs <- rpar (force (primesBtwn (hf + 1) lim))
            return (as ++ bs)

      forkIO $ putStrLn ("\nPrimes are: " ++ (show result) ++ " for " ++ n ++ "\n")
      loop

-- Compute primes between two integers
-- Deliberately inefficient for demonstration purposes
primesBtwn n m = eratos [n..m]
  where
    eratos []     = []
    eratos (p:xs) = p : eratos (xs `minus` [p, p+p..])

Ejecutando esto demostrará el comportamiento concurrente:

Enter a number
12
Enter a number

Primes are: [2,3,5,7,8,9,10,11,12] for 12

100
Enter a number

Primes are: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100] for 100

200000000
Enter a number
-- waiting for 200000000    
200
Enter a number

Primes are: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200] for 200

-- still waiting for 200000000

rseq

Podemos usar rseq :: Strategy a para forzar un argumento a una forma normal de cabeza débil:

f1 :: [Int]
f1 = [1..100000000]

f2 :: [Int]
f2 = [1..200000000]

main = runEval $ do
  a <- rpar (f1) -- this'll take a while...
  b <- rpar (f2) -- this'll take a while and then some...
  rseq a
  return (a,b)

Esto cambia sutilmente la semántica del ejemplo rpar ; mientras que el último sería volver de inmediato, mientras que el cálculo de los valores en el fondo, este ejemplo esperará hasta que a se puede evaluar a WHNF.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow