Sök…


parametrar

Typ / funktion Detalj
data Eval a Eval är en Monad som gör det lättare att definiera parallella strategier
type Strategy a = a -> Eval a en funktion som förkroppsligar en parallell utvärderingsstrategi. Funktionen går igenom (delar av) dess argument och utvärderar subexpressions parallellt eller i följd
rpar :: Strategy a gnister sitt argument (parallellt för utvärdering)
rseq :: Strategy a utvärderar sitt argument till svag huvud normal form
force :: NFData a => a -> a utvärderar hela strukturen i argumentet, reducerar det till normal form innan argumentet returneras. Den tillhandahålls av modulen Control.DeepSeq

Anmärkningar

Simon Marlows bok , Concurrent and Parallel Programming in Haskell, är enastående och täcker en mängd begrepp. Det är också mycket tillgängligt för även den nyaste Haskell-programmeraren. Det rekommenderas starkt och finns tillgängligt i PDF eller online gratis.

Parallell kontra samtidigt

Simon Marlow uttrycker det bäst :

Ett parallellt program är ett som använder en mängd beräkningshårdvara (t.ex. flera processorkärnor) för att utföra en beräkning snabbare. Målet är att komma fram till svaret tidigare genom att delegera olika delar av beräkningen till olika processorer som kör samtidigt.

Däremot är samtidighet en programstruktureringsteknik där det finns flera styrtrådar. Konceptuellt utför styrtrådarna "samtidigt"; det vill säga användaren ser deras effekter sammanflätade. Huruvida de faktiskt körs samtidigt eller inte är en implementeringsdetalj; ett samtidigt program kan köras på en enda processor genom interleaved exekvering eller på flera fysiska processorer.

Svagt huvud Normal form

Det är viktigt att vara medveten om hur lat utvärdering fungerar. Det första avsnittet i detta kapitel kommer att ge en stark introduktion till WHNF och hur detta relaterar till parallell och samtidig programmering.

Eval Monad

Parallelism i Haskell kan uttryckas med hjälp av Eval Monad från Control.Parallel.Strategies , med hjälp av rpar och rseq funktionerna (bland andra).

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)

Om du kör main ovan körs och "återgår" omedelbart, medan de två värdena, a och b beräknas i bakgrunden genom rpar .

Obs: se till att du kompilerar med -threaded för att parallellkörning ska ske.

RPAR

rpar :: Strategy a genomför den givna strategin (återkall: type Strategy a = a -> Eval a ) parallellt:

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..])

Att köra detta kommer att visa det samtidiga beteendet:

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

Vi kan använda rseq :: Strategy a att tvinga ett argument till svagt huvud normal form:

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)

Detta förändrar subtilt semantiken i rpar exemplet; Det sistnämnda skulle återvända omedelbart medan beräkningen av värdena i bakgrunden väntar detta exempel tills a kan utvärderas till WHNF.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow