gpt4 book ai didi

performance - 如何在 Haskell 中获得 5GB 堆的控制权?

转载 作者:行者123 更新时间:2023-12-03 06:11:18 25 4
gpt4 key购买 nike

目前,我正在尝试使用 Snap 编写的一个小型 Haskell Web 服务器,该服务器加载并向客户端提供大量数据。我很难控制服务器进程。该进程有时会在数秒到数分钟内使用大量 CPU,并且对客户端请求无响应。有时,内存使用量会在几秒钟内激增(有时会下降)数百兆字节。

希望有人对长时间运行的使用大量内存的 Haskell 进程有更多的经验,并且可以给我一些指导,使事情更加稳定。我已经调试这个东西好几天了,我开始有点绝望了。

我的设置的一些概述:

  • 在服务器启动时,我将大约 5 GB 的数据读取到内存中的一个大(嵌套)Data.Map 类似结构中。嵌套映射是值严格的,映射内的所有值都是数据类型,其所有字段也都是严格的。我花了很多时间来确保不留下任何未评估的重击。导入(取决于我的系统负载)大约需要 5-30 分钟。奇怪的是,连续运行的波动比我预期的要大得多,但这是一个不同的问题。

  • 大数据结构位于“TVar”内,该“TVar”由 Snap 服务器生成的所有客户端线程共享。客户端可以使用小型查询语言请求数据的任意部分。数据请求量通常很小(最多300kb左右)并且只涉及数据结构的一小部分。所有只读请求均使用“readTVarIO”完成,因此不需要任何 STM 事务。

  • 服务器使用以下标志启动:+RTS -N -I0 -qg -qb。这将以多线程模式启动服务器,禁用空闲时间和并行 GC。这似乎大大加快了进程。

服务器基本上运行没有任何问题。然而,客户端请求时不时会超时,CPU 峰值达到 100%(甚至超过 100%),并持续很长一段时间。同时服务器不再响应请求。

我认为可能导致 CPU 使用率的原因如下:

  • 该请求需要花费大量时间,因为有大量工作要做。这有点不太可能,因为有时会发生这种情况,这些请求在之前的运行中被证明非常快(我的意思是 20-80 毫秒左右)。

  • 在处理数据并将其发送到客户端之前,仍然需要计算一些未评估的 thunk。这也不太可能,原因与上一点相同。

  • 垃圾收集不知何故启动并开始扫描我的整个 5GB 堆。我可以想象这会占用很多时间。

问题是我不知道如何弄清楚到底发生了什么以及该怎么办。因为导入过程需要很长时间,所以分析结果没有向我显示任何有用的东西。似乎无法从代码内有条件地打开和关闭探查器。

我个人怀疑GC是这里的问题。我正在使用 GHC7,它似乎有很多选项可以调整 GC 的工作方式。

当使用数据通常非常稳定的大型堆时,您建议采用什么 GC 设置?

最佳答案

大量内存使用和偶尔的 CPU 峰值几乎肯定是 GC 启动的原因。您可以使用 -B 等 RTS 选项来查看情况是否确实如此,这会导致 GHC 在出现问题时发出蜂鸣声主要集合,-t 会告诉您事后统计信息(特别是查看 GC 时间是否真的很长)或 -Dg,它打开调试信息用于 GC 调用(尽管您需要使用 -debug 进行编译)。

您可以采取多种措施来缓解此问题:

  • 在最初导入数据时,GHC 浪费了大量时间来增加堆。您可以通过指定一个大的 -H 来告诉它立即获取您需要的所有内存。

  • 具有稳定数据的大堆将被提升到老一代。如果使用 -G 增加代数,则可能能够将稳定的数据置于最古老、很少进行 GC 的代中,而您拥有更传统的年轻堆和老堆上面。

  • 根据应用程序其余部分的内存使用情况,您可以使用 -F 来调整 GHC 在再次收集老一代之前允许其增长的量。您可以调整此参数来收集这些非垃圾。

  • 如果没有写入,并且您有一个定义良好的接口(interface),则可能值得让该内存不由 GHC 管理(使用 C FFI),这样就不会有 super GC 的机会曾经。

这些都是猜测,因此请使用您的特定应用程序进行测试。

关于performance - 如何在 Haskell 中获得 5GB 堆的控制权?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6623391/

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