Szukaj…


Parametry

Typ / funkcja Szczegół
data Eval a Eval to monada, która ułatwia definiowanie równoległych strategii
type Strategy a = a -> Eval a funkcja obejmująca równoległą strategię oceny. Funkcja przemierza (części) swojego argumentu, oceniając podwyrażenia równolegle lub po kolei
rpar :: Strategy a wyrzuca swój argument (do równoległej oceny)
rseq :: Strategy a ocenia swój argument na słabą normalną formę głowy
force :: NFData a => a -> a ocenia całą strukturę argumentu, redukując go do normalnej formy, przed zwróceniem samego argumentu. Zapewnia to moduł Control.DeepSeq

Uwagi

Książka Simona Marlowa „ Programowanie równoległe i równoległe w Haskell” jest znakomita i obejmuje wiele koncepcji. Jest również bardzo dostępny dla nawet najnowszego programisty Haskell. Jest wysoce zalecane i dostępne w formacie PDF lub online za darmo.

Równoległe vs Współbieżne

Simon Marlow mówi najlepiej :

Program równoległy to taki, który wykorzystuje wiele sprzętów obliczeniowych (np. Kilka rdzeni procesora) do szybszego wykonywania obliczeń. Celem jest wcześniejsze uzyskanie odpowiedzi, delegowanie różnych części obliczeń do różnych procesorów wykonujących się w tym samym czasie.

Natomiast współbieżność jest techniką konstruowania programu, w której istnieje wiele wątków kontroli. Koncepcyjnie wątki kontroli wykonują się „w tym samym czasie”; to znaczy, użytkownik widzi, że ich efekty są przeplatane. To, czy faktycznie wykonują się w tym samym czasie, czy nie, jest szczegółem implementacji; współbieżny program może być wykonywany na jednym procesorze poprzez przeplatanie lub na wielu procesorach fizycznych.

Słaba głowa normalna forma

Ważne jest, aby zdawać sobie sprawę z tego, jak działa leniwa ocena. Pierwsza sekcja tego rozdziału da mocne wprowadzenie do WHNF i tego, jak odnosi się to do programowania równoległego i współbieżnego.

The Eval Monad

Równoległość Haskell może być wyrażona za pomocą Eval monadę z Control.Parallel.Strategies , stosując rpar i rseq funkcji (między innymi).

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)

Uruchamianie main powyżej będą wykonanie i „powrót” niezwłocznie, natomiast dwie wartości, i a b są obliczane w tle poprzez rpar .

Uwaga: upewnij się, że kompilujesz z -threaded aby -threaded równoległe wykonanie.

rpar

rpar :: Strategy a wykonuje daną strategię (przywołaj: type Strategy a = a -> Eval a ) równolegle:

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

Uruchomienie tego zademonstruje współbieżne zachowanie:

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

Możemy użyć rseq :: Strategy a aby wymusić argument na rzecz postaci słabej głowy:

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)

To subtelnie zmienia semantykę przykładu rpar ; natomiast druga wróci natychmiast podczas obliczania wartości w tle, w tym przykładzie będzie czekać aż można ocenić na WHNF. a



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow