我有一个程序,我试图并行化(完全粘贴可运行代码here)。并行哈斯克尔 - GHC GC'ing火花
我已经介绍过并发现大部分时间都花在findNearest
之上,这实际上是一个简单的foldr
,而不是一个大的Data.Map
。
findNearest :: RGB -> M.Map k RGB -> (k, Word32)
findNearest rgb m0 =
M.foldrWithKey' minDistance (k0, distance rgb r0) m0
where (k0, r0) = M.findMin m0
minDistance k r [email protected](_, d1) =
-- Euclidean distance in RGB-space
let d0 = distance rgb r
in if d0 < d1 then (k, d0) else x
parFindNearest
应该并联在较大Map
的子树执行findNearest
。
parFindNearest :: NFData k => RGB -> M.Map k RGB -> (k, Word32)
parFindNearest rgb = minimumBy (comparing snd)
. parMap rdeepseq (findNearest rgb)
. M.splitRoot
不幸的是,GHC GC是我的火花之前,他们转换成有用的并行。
下面是与ghc -O2 -threaded
编译并与+RTS -s -N2
839,892,616 bytes allocated in the heap
123,999,464 bytes copied during GC
5,320,184 bytes maximum residency (19 sample(s))
3,214,200 bytes maximum slop
16 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 1550 colls, 1550 par 0.23s 0.11s 0.0001s 0.0004s
Gen 1 19 colls, 18 par 0.11s 0.06s 0.0030s 0.0052s
Parallel GC work balance: 16.48% (serial 0%, perfect 100%)
TASKS: 6 (1 bound, 5 peak workers (5 total), using -N2)
SPARKS: 215623 (1318 converted, 0 overflowed, 0 dud, 198111 GC'd, 16194 fizzled)
INIT time 0.00s ( 0.00s elapsed)
MUT time 3.72s ( 3.66s elapsed)
GC time 0.34s ( 0.17s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 4.07s ( 3.84s elapsed)
Alloc rate 225,726,318 bytes per MUT second
Productivity 91.6% of total user, 97.1% of total elapsed
gc_alloc_block_sync: 9862
whitehole_spin: 0
gen[0].sync: 0
gen[1].sync: 2103
运行正如你所看到的结果,大多数火花都GC'd或转换之前以失败告终。我尝试过使用不同的严格性,让findNearest
返回一个自定义严格配对数据类型而不是元组 ,或使用Control.Parallel.Strategies
的rdeepseq,但我的火花仍然是GC'd。
我想知道
- 为什么我的火花被转换之前GC'd?
- 我该如何改变我的程序以利用并行性?
http://www.haskell.org/haskellwiki/ThreadScope可能会有所帮助。 –
1.'splitRoot'通常生成一个包含三个元素的列表,即左树,右树和右树。所以你通过_very_小列表使用'parMap'。元素本身非常大,但是'findNearest'又不是平行的。 2.如果未使用,则触发的表达式为GC'd。也许你毕竟没有使用结果? – Zeta
@Zeta:是的,列表的大小很小(只有3个元素),但Map的大小很大(65k〜250k元素),所以即使将它分割成两个大的子树也应该提供一些有用的并行性。 – cdk