Я пытаюсь узнать, как использовать модуль Control.Parallel
, но я думаю, что я не понял его.Многоядерное программирование в Haskell - Control.Parallel
Я пытаюсь запустить следующий код (fibs.hs).
import Control.Parallel
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = p `par` (q `pseq` (p + q))
where
p = fib (n-1)
q = fib (n-2)
main = print $ fib 30
Я составил это с:
ghc -O2 --make -threaded fibs.hs
И тогда я получаю следующие результаты, исполняющие эту программу (вывод скрипта Python, который работает каждую программу в 100 раз и возвращает среднее и стандартное отклонение время выполнения):
./fibs +RTS -N1 -> avg= 0.060203 s, deviation = 0.004112 s
./fibs +RTS -N2 -> avg= 0.052335 s, deviation = 0.006713 s
./fibs +RTS -N3 -> avg= 0.052935 s, deviation = 0.006183 s
./fibs +RTS -N4 -> avg= 0.053976 s, deviation = 0.007106 s
./fibs +RTS -N5 -> avg= 0.055227 s, deviation = 0.008598 s
./fibs +RTS -N6 -> avg= 0.055703 s, deviation = 0.006537 s
./fibs +RTS -N7 -> avg= 0.058327 s, deviation = 0.007526 s
Мои вопросы:
Что именно происходит, когда я оцениваю:
a `par` (b `pseq` (a + b)) ?
Я понимаю, что
par
б должен намекнуть компилятор о рассчет параллельно с Ъ и Ь вернуться. ОК. Но что делаетpseq
?Почему я вижу такое небольшое увеличение производительности? Я запускаю это в четырехъядерном процессоре Intel Core 2. Я ожидаю, что работа с -N5 или -N6 не повлияет на производительность или что программа действительно начнет работать очень плохо. Но почему я не вижу улучшения от -N2 до -N3 и почему первоначальное улучшение настолько мало?
Неужели Haskell автоматически балансирует искры, чтобы получить лучшую производительность? – Chuck
Он автоматически уравновешивает потоки. В среде выполнения есть очереди неоцененных выражений (искры), которые будут преобразованы в потоки при уменьшении рабочих нагрузок. Вам все равно не создавать слишком много искр (и, таким образом, тратить время на заполнение очереди искры) –