我有一個程序,我試圖並行化(完全粘貼可運行代碼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