gpt4 book ai didi

Haskell - parMap 怎么了?

转载 作者:行者123 更新时间:2023-12-02 17:13:26 26 4
gpt4 key购买 nike

我已经运行了一些测试:

import Control.Parallel.Strategies
import Data.Vector as V
import Data.Maybe

parMapVec :: (a -> b) -> Vector a -> Vector b
parMapVec f v = runEval $ evalTraversable rpar $ V.map f v

range :: Integer -> Integer -> Vector Integer
range x y
| x == y = x `cons` empty
| x < y = x `cons` (range (x + 1) y)
| x > y = (range x (y + 1)) `snoc` y

fac :: Integer -> Integer
fac n
| n < 2 = 1
| otherwise = n * (fac $ n - 1)

main :: IO ()
main = do
let result = runEval $ do
let calc = parMapVec fac $ 80000 `range` 80007
rseq calc
return calc
putStrLn $ show result

以及对 main 的以下修改,以确保我的 parMapVector 没有问题:

main = do
let result = runEval $ do
let calc = parMap rpar fac [80000..80007]
rseq calc
return calc
putStrLn $ show result

我用 gch --make parVectorTest.hs -threaded -rtsopts 编译并用 ./parVectorTest -s 运行。

这是我在带有矢量的版本中发现的:

56,529,547,832 bytes allocated in the heap
10,647,896,984 bytes copied during GC
7,281,792 bytes maximum residency (16608 sample(s))
3,285,392 bytes maximum slop
21 MB total memory in use (0 MB lost due to fragmentation)

Tot time (elapsed) Avg pause Max pause
Gen 0 82708 colls, 0 par 0.828s 0.802s 0.0000s 0.0016s
Gen 1 16608 colls, 0 par 15.006s 14.991s 0.0009s 0.0084s

TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)

SPARKS: 8 (7 converted, 0 overflowed, 0 dud, 0 GC'd, 1 fizzled)

INIT time 0.001s ( 0.001s elapsed)
MUT time 5.368s ( 5.369s elapsed)
GC time 15.834s ( 15.793s elapsed)
EXIT time 0.001s ( 0.000s elapsed)
Total time 21.206s ( 21.163s elapsed)

Alloc rate 10,530,987,847 bytes per MUT second

Productivity 25.3% of total user, 25.4% of total elapsed

gc_alloc_block_sync: 0
whitehole_spin: 0
gen[0].sync: 0
gen[1].sync: 0

这很好,只是我在我的系统监视器上观察了进程执行,并且一次只有一个核心在工作。每次打印出其中一个结果时,该过程就会切换到不同的核心。所以我认为我的 parMapVec 函数有问题。但是后来我做了同样的事情,除了带有列表的版本:

56,529,535,488 bytes allocated in the heap
12,483,967,024 bytes copied during GC
6,246,872 bytes maximum residency (19843 sample(s))
2,919,544 bytes maximum slop
20 MB total memory in use (0 MB lost due to fragmentation)

Tot time (elapsed) Avg pause Max pause
Gen 0 79459 colls, 0 par 0.818s 0.786s 0.0000s 0.0009s
Gen 1 19843 colls, 0 par 17.725s 17.709s 0.0009s 0.0087s

TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)

SPARKS: 16 (14 converted, 0 overflowed, 0 dud, 1 GC'd, 1 fizzled)

INIT time 0.001s ( 0.001s elapsed)
MUT time 5.394s ( 5.400s elapsed)
GC time 18.543s ( 18.495s elapsed)
EXIT time 0.000s ( 0.000s elapsed)
Total time 23.940s ( 23.896s elapsed)

Alloc rate 10,479,915,927 bytes per MUT second

Productivity 22.5% of total user, 22.6% of total elapsed

gc_alloc_block_sync: 0
whitehole_spin: 0
gen[0].sync: 0
gen[1].sync: 0

所以有更多的垃圾收集,这是有道理的。还有更多的 Spark ,我不知道如何解释。当我在系统监视器上观察它执行时,该程序表现出相同的行为。

由于对 this question 的回答,我还使用 ./parVector -s -C0.01 运行了两个测试。并得到基本相同的结果。我在运行 Ubuntu Linux 17.04 的 Lenovo Ideapad,8 核。在测试时,我唯一打开的应用程序是 VS Code 和我的系统监视器,尽管其他进程占用了很小一部分的处理能力。处理器是否必须完全空闲才能产生 Spark ?

最佳答案

默认情况下,GHC 使用单个操作系统线程运行所有程序,即使启用了-threaded。请注意输出中的文本“using -N1”——它表示程序正在使用 1 个物理线程运行。

简而言之:通过例如+RTS -N8 到你的程序。有关此标志的文档,请参阅 here .


从广义上讲,这是由于并行和并发的区别。 Here are some所以试图解释差异的问题。区别可以概括为:

  • 并行性:将任务分割为类似的 block ,以便在某个时间点在不同的核心/CPU 上同时运行;为了提高速度

  • 并发性:多个任务在概念上独立执行,因此它们的执行时间重叠,无论是通过时间片在同一线程上还是在不同的核心/CPU 上;通常更有效地利用共享资源

但是,这些定义有些争议;有时两者含义相反,有时可互换使用。但是,为了理解这个问题(为什么除了 -threaded 之外还必须传递另一个标志以使“并行”程序实际并行运行),我相信它们是有用的定义。

关于Haskell - parMap 怎么了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47956309/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com