Haskell Language
параллелизм
Поиск…
параметры
Тип / Функция | подробность |
---|---|
data Eval a | Eval - это Монада, которая упрощает определение параллельных стратегий |
type Strategy a = a -> Eval a | функция, которая воплощает параллельную стратегию оценки. Функция проходит (части) своего аргумента, оценивая подвыражения параллельно или последовательно |
rpar :: Strategy a | искры его аргумента (для параллельной оценки) |
rseq :: Strategy a | оценивает свой аргумент на слабую головную нормальную форму |
force :: NFData a => a -> a | оценивает всю структуру своего аргумента, сводя его к нормальной форме, прежде чем возвращать сам аргумент. Он обеспечивается модулем Control.DeepSeq |
замечания
Книга Саймона Марлоу « Параллельное и параллельное программирование в Хаскелле» является выдающейся и охватывает множество концепций. Он также очень доступен даже для самого нового программиста Haskell. Он настоятельно рекомендуется и доступен в формате PDF или онлайн бесплатно.
Параллельные и параллельные
Саймон Марлоу делает это лучше всего :
Параллельная программа - это программа, которая использует множество вычислительных аппаратных средств (например, несколько процессорных ядер) для более быстрого вычисления вычислений. Цель состоит в том, чтобы прийти к ответу ранее, делегируя разные части вычислений различным процессорам, которые выполняются одновременно.
Напротив, параллелизм - это метод структурирования программ, в котором есть несколько потоков управления. Понятно, что потоки управления выполняются «одновременно»; то есть пользователь видит, что их эффекты чередуются. Выполняются ли они в одно и то же время или нет, это деталь реализации; параллельная программа может выполняться на одном процессоре посредством выполнения с чередованием или на нескольких физических процессорах.
Нормальная форма слабой головы
Важно знать, как работает ленивая оценка. Первый раздел этой главы даст сильное введение в WHNF и то, как это относится к параллельному и параллельному программированию.
Эвальская Монада
Параллельность в Haskell может быть выражена с помощью Eval
Monad из Control.Parallel.Strategies
, используя функции rpar
и rseq
(среди прочего).
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)
Выполнение main
выше будет выполняться и «немедленно возвращаться», в то время как два значения a
и b
вычисляются в фоновом режиме через rpar
.
Примечание: убедитесь, что вы -threaded
компиляцию с -threaded
для параллельного выполнения.
RPAR
rpar :: Strategy a
выполняет данную стратегию (напомните: type Strategy a = a -> Eval a
) параллельно:
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..])
Выполнение этого будет демонстрировать одновременное поведение:
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
Мы можем использовать rseq :: Strategy a
чтобы заставить аргумент «Нормальная форма слабой головы»:
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)
Это тонко изменяет семантику rpar
примера; в то время как последний будет немедленно вернуться в то время вычисления значений в фоновом режиме, этот пример будет ждать , пока не может быть оценена в WHNF. a