use*_*324 7 memory multithreading garbage-collection haskell ghc
我有一个Scotty api服务器,它构造一个Elasticsearch查询,从ES获取结果并呈现json.
与凤凰城和杜松子酒等其他服务器相比,我通过使用BloodHound获得更高的CPU利用率和吞吐量来提供ES响应,但是Gin和Phoenix在内存效率方面比Scotty更好.
Scotty的统计数据
wrk -t30 -c100 -d30s "http://localhost:3000/filters?apid=1&hfa=true"
Running 30s test @ http://localhost:3000/filters?apid=1&hfa=true
30 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 192.04ms 305.45ms 1.95s 83.06%
Req/Sec 133.42 118.21 1.37k 75.54%
68669 requests in 30.10s, 19.97MB read
Requests/sec: 2281.51
Transfer/sec: 679.28KB
Run Code Online (Sandbox Code Playgroud)
这些统计数据在我的Mac上安装了GHC 7.10.1
处理器信息2.5GHx i5
内存信息8GB 1600 Mhz DDR3
基于轻量级线程的GHC并发性让我印象深刻,但内存效率仍然是一个大问题.
分析内存使用情况产生了以下统计数据
39,222,354,072 bytes allocated in the heap
277,239,312 bytes copied during GC
522,218,848 bytes maximum residency (14 sample(s))
761,408 bytes maximum slop
1124 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 373 colls, 373 par 2.802s 0.978s 0.0026s 0.0150s
Gen 1 14 colls, 13 par 0.534s 0.166s 0.0119s 0.0253s
Parallel GC work balance: 42.38% (serial 0%, perfect 100%)
TASKS: 18 (1 bound, 17 peak workers (17 total), using -N4)
SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
INIT time 0.001s ( 0.008s elapsed)
MUT time 31.425s ( 36.161s elapsed)
GC time 3.337s ( 1.144s elapsed)
EXIT time 0.000s ( 0.001s elapsed)
Total time 34.765s ( 37.314s elapsed)
Alloc rate 1,248,117,604 bytes per MUT second
Productivity 90.4% of total user, 84.2% of total elapsed
gc_alloc_block_sync: 27215
whitehole_spin: 0
gen[0].sync: 8919
gen[1].sync: 30902
Run Code Online (Sandbox Code Playgroud)
我相信GHC使用GC的标记和扫描策略.我也相信使用类似于Erlang VM的每线程增量GC策略可以更好地提高内存效率.
通过解释Don Stewart对相关问题的回答,必须有一些方法来改变GHC中的GC策略.
我还注意到,当并发级别较低时,内存使用率保持稳定且相当低,因此我认为只有当并发性很高时,内存使用量才会增加.
任何想法/指针来解决这个问题.
http://community.haskell.org/~simonmar/papers/local-gc.pdf
Simon Marlow 的这篇论文描述了每线程本地堆,并声称这是在 GHC 中实现的。它的日期是 2011 年。我不确定这是否是当前版本的 GHC 实际所做的(即,这是否进入 GHC 的发行版本,是否仍然是当前的现状,等等),但似乎我的回忆并不完全是凭空捏造的。
我还将指出 GHC 手册中解释您可以调整垃圾收集器的设置的部分:
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/runtime-control.html#rts-options-gc
特别是,默认情况下,GHC 使用 2 空间收集器,但添加-cRTS 选项使其使用稍慢的 1 空间收集器,这应该会消耗更少的 RAM。(我完全不清楚此信息适用于哪一代。)
我的印象是 Simon Marlow 负责大部分 RTS 工作(包括垃圾收集器),所以如果你能在 IRC 上找到他,他就是那个会问你是否想要直接真相的人......