gpt4 book ai didi

尽管总内存使用量只有 22Mb,但 Haskell 线程堆溢出?

转载 作者:行者123 更新时间:2023-12-03 04:39:36 25 4
gpt4 key购买 nike

我正在尝试并行化光线追踪器。这意味着我有一个很长的小计算列表。普通程序在特定场景上运行需要 67.98 秒,总内存使用量为 13 MB,生产率为 99.2%。

在我的第一次尝试中,我使用了并行策略 parBuffer缓冲区大小为 50。我选择 parBuffer因为它遍历列表的速度与 Spark 消耗的速度一样快,并且不会像parList那样强制列表的主干。 ,这会使用大量内存,因为列表很长。与-N2 ,它的运行时间为 100.46 秒,总内存使用量为 14 MB,生产率为 97.8%。 Spark 信息为:SPARKS: 480000 (476469 converted, 0 overflowed, 0 dud, 161 GC'd, 3370 fizzled)

嘶嘶 Spark 的比例较大,说明 Spark 的粒度太小,所以接下来我尝试使用策略parListChunk ,它将列表分成 block 并为每个 block 创建一个 Spark 。我得到了最好的结果, block 大小为 0.25 * imageWidth 。该程序运行时间为 93.43 秒,总内存使用量为 236 MB,生产率为 97.3%。 Spark 信息为:SPARKS: 2400 (2400 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled) 。我相信更大的内存使用是因为 parListChunk强制列表的主干。

然后我尝试编写自己的策略,将列表惰性地划分为 block ,然后将 block 传递给 parBuffer并将结果连接起来。

 concat $ withStrategy (parBuffer 40 rdeepseq) (chunksOf 100 (map colorPixel pixels))

运行时间为 95.99 秒,总内存使用量为 22MB,生产率为 98.8%。这是成功的,因为所有的 Spark 都被转换并且内存使用量低得多,但速度没有提高。这是事件日志配置文件的一部分的图像。 Event log profile

正如您所看到的,线程由于堆溢出而被停止。我尝试添加 +RTS -M1G这会将默认堆大小一直增加到 1Gb。结果没有改变。我读到 Haskell 主线程如果堆栈溢出将使用堆中的内存,所以我也尝试使用 +RTS -M1G -K1G 增加默认堆栈大小。但这也没有影响。

还有什么我可以尝试的吗?如果需要,我可以发布更详细的内存使用情况或事件日志分析信息,我没有包含所有这些信息,因为它是很多信息,而且我认为没有必要包含所有这些信息。

编辑:我正在阅读有关 Haskell RTS multicore support 的内容,它谈到每个核心都有一个 HEC(Haskell 执行上下文)。除其他外,每个 HEC 还包含一个分配区域(它是单个共享堆的一部分)。每当任何 HEC 的分配区域耗尽时,就必须执行垃圾收集。似乎是 RTS option控制它,-A。我尝试了 -A32M 但没有看到任何区别。

编辑2: Here is a link to a github repo dedicated to this question 。我已将分析结果包含在分析文件夹中。

EDIT3:这是相关的代码:

render :: [([(Float,Float)],[(Float,Float)])] -> World -> [Color]
render grids world = cs where
ps = [ (i,j) | j <- reverse [0..wImgHt world - 1] , i <- [0..wImgWd world - 1] ]
cs = map (colorPixel world) (zip ps grids)
--cs = withStrategy (parListChunk (round (wImgWd world)) rdeepseq) (map (colorPixel world) (zip ps grids))
--cs = withStrategy (parBuffer 16 rdeepseq) (map (colorPixel world) (zip ps grids))
--cs = concat $ withStrategy (parBuffer 40 rdeepseq) (chunksOf 100 (map (colorPixel world) (zip ps grids)))

网格是由 colorPixel 预先计算和使用的随机 float 。 colorPixel 的类型是:

 colorPixel :: World -> ((Float,Float),([(Float,Float)],[(Float,Float)])) -> Color

最佳答案

不是问题的解决方案,而是原因的提示:

Haskell 在内存重用方面似乎非常保守,当解释器看到回收内存块的潜力时,它就会这样做。您的问题描述符合此处描述的次要 GC 行为(底部) https://wiki.haskell.org/GHC/Memory_Management .

New data are allocated in 512kb "nursery". Once it's exhausted, "minor GC" occurs - it scans the nursery and frees unused values.

因此,如果您将数据切成更小的 block ,则可以使引擎更早地进行清理 - GC 就会启动。

关于尽管总内存使用量只有 22Mb,但 Haskell 线程堆溢出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31641464/

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