concurrent.futures的RSS内存使用情况



我有一个简单的脚本,试图强调concurrent.futures库,如下所示:

#! /usr/bin/python
import psutil
import gc
import os
from concurrent.futures import ThreadPoolExecutor
WORKERS=2**10
def run():
def x(y):
pass
with ThreadPoolExecutor(max_workers=WORKERS) as pool:
for _ in pool.map(x, [i for i in range(WORKERS)]):
pass
if __name__ == '__main__':
print('%d objects' % len(gc.get_objects()))
print('RSS: %s kB' % (psutil.Process(os.getpid()).get_memory_info().rss / 2**10))
run()
print('%d objects' % len(gc.get_objects()))
print('RSS: %s kB' % (psutil.Process(os.getpid()).get_memory_info().rss / 2**10))

它最终在运行python2.7的2核linux机器上产生以下输出:

# time ./test.py
7048 objects
RSS: 11968 kB
6749 objects
RSS: 23256 kB
real    0m1.077s
user    0m0.875s
sys     0m0.316s

尽管这是一个有点做作的例子,但我很难理解为什么RSS在这种情况下会增加,以及分配的内存用于什么。

Linux应该使用COW很好地处理分叉内存,但由于CPython是引用计数的,因此继承的内存部分不会是真正只读的,因为引用需要更新。考虑到引用计数开销是多么的小,12MB的增加让我感到惊讶。如果我不使用ThreadPoolExecutor,而是使用threading库生成守护进程线程,RSS只会增加4MB。

目前我还不清楚是怀疑CPython分配器还是glibc分配器,但我的理解是后者应该处理这种类型的并发性,并能够重用arena在派生线程之间进行分配。

我在python 2.7.9下使用concurrent.futures 3.0.3的后端口版本,在4.1内核上使用glibc 2.4。如有任何关于如何对此进行进一步调查的建议或提示,我们将不胜感激。

大多数内存分配器不会将所有内存返回到操作系统。

尝试调用run()两次,并在第二次调用之前/之后检查RSS。

(也就是说,荒谬的线程数量通常不是一个好主意(

我建议您阅读https://stackoverflow.com/a/1718522/5632150

正如他所说,您可以派生的线程数量取决于您的线程是否执行任何I/O操作。如果是这样的话,有一些方法可以优化这个问题。如果不是,我通常会执行MAX_THREADS=N_CORES+1。

不确定,但是,你想在一个核心上生成1024个线程吗?

最新更新