Haskell: почему следующие запускаются последовательно? - PullRequest
0 голосов
/ 27 мая 2018

Добрый день.Данный код

import           Control.DeepSeq
import           Control.Exception
import           Control.Parallel
import           Control.Parallel.Strategies
import           System.Environment
import           Text.Printf

l = [34,56,43,1234,456,765,345,4574,58,878,978,456,34,234,1234123,1234,12341234]
f x = Just (sum [1..x])

fun1 :: [Maybe Integer]
fun1 = map f l `using` parList rdeepseq
fun2 :: [Maybe Integer]
fun2 = map f l `using` evalList (rparWith rdeepseq)
fun3 :: [Maybe Integer]
fun3 = map f l `using` evalList (rpar . force)

main :: IO ()
main = print fun1

Почему fun1 и fun2 работают последовательно?Из того, что я понял, rparWith должен зажечь свой аргумент.Ответ здесь утверждает то же самое.Но для fun1 и fun2 я получаю вывод типа «SPARKS: 0 (0 конвертировано, 0 переполнено, 0 dud, 0 GC'd, 0 fizzled)».Так что Искры даже не были созданы.fun3 работает как положено с созданием искр.Ты за помощь

UPD: И я обнаружил, что rdeepseq делает пример из книги (параллельное и параллельное программирование в Haskell) работает последовательно.Книга говорит:

И мы можем использовать parPair для написания Стратегии, которая полностью оценивает оба компонента пары параллельно:

parPair rdeepseq rdeepseq :: (NFData a, NFData b)=> Стратегия (a, b)

Чтобы разбить, что происходит, когда эта Стратегия применяется к паре: parPair вызывает, а evalPair вызывает rparWith rdeepseq для каждого компонента пары.Таким образом, эффект состоит в том, что каждый компонент будет полностью оценен в нормальной форме параллельно.

Но если я запусту

(Just (fib 35), Just (fib 36)) `using` parPair rdeepseq rdeepseq

или даже

(fib 35, fib 36) `using` parPair rdeepseq rdeepseq

В Threadscope отображается только одно работающее ядро ​​и создано 0 искр.

fib реализован следующим образом (из книги)

fib :: Integer -> Integer
fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

Ответы [ 2 ]

0 голосов
/ 18 июля 2018

rparWith было определено с использованием realWorld#, глубоко магического внутреннего значения GHC.То, как оно использовалось, по сути аналогично применению «функции», иногда называемой accursedUnutterablePerformIO (более официально, unsafeInlinePerformIO).Его использование допустимо только тогда, когда рассматриваемый IO на самом деле исключительно чистый.Мысль была такова, что, поскольку Eval только для расчета, это должно быть хорошо.Но на самом деле искрение нитей - это IO эффект, и мы о нем заботимся!Оптимизатор перестраивал эти эффекты неудачным способом, в результате чего их в конечном итоге отбрасывали.Исправление должно было использовать unsafeDupablePerformIO вместо.Это намного лучше "функция", и, кажется, делает свое дело.Подробности смотрите в билете .

Примечание: мое первоначальное исправление оказалось немного неправильным;теперь он снова изменен.

0 голосов
/ 28 мая 2018

Оригинальная бумага описывает rdeepseq как

rdeepseq :: NFData a => Strategy a
rdeepseq x = rnf x ‘pseq‘ return x

И действительно, если вы воспользуетесь этим определением, оно создаст искры, как и следовало ожидать.Похоже, rdeepseq семантика была изменения (вероятно, здесь ), намеренно или случайно.Я не вижу никаких примечаний ни в документации, ни в журнале изменений, так что это, вероятно, ошибка.Пожалуйста, создайте проблему на их баг-трекере и попросите сопровождающих дать разъяснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...