来自 concurrent.futures 的 RSS 内存使用情况
RSS memory usage from concurrent.futures
我有一个简单的脚本试图强调 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))
最终在 2 核 linux 机器上产生以下输出 运行 python 2.7:
# 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。任何有关如何进一步调查此问题的建议或提示将不胜感激。
我建议您阅读来自
的回复
正如他所说,您可以生成的线程数取决于您的线程是否执行任何 I/O 操作。如果是这样,有一些方法可以优化这个问题。如果不是我通常做 MAX_THREADS = N_CORES + 1.
不确定,但您是否尝试在一个核心上生成 1024 个线程?
大多数内存分配器不会return 所有它们的内存到OS。
尝试调用 run()
两次并在第二次检查 RSS before/after。
(也就是说,荒谬的线程数通常不是一个好主意)
我有一个简单的脚本试图强调 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))
最终在 2 核 linux 机器上产生以下输出 运行 python 2.7:
# 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。任何有关如何进一步调查此问题的建议或提示将不胜感激。
我建议您阅读来自
的回复正如他所说,您可以生成的线程数取决于您的线程是否执行任何 I/O 操作。如果是这样,有一些方法可以优化这个问题。如果不是我通常做 MAX_THREADS = N_CORES + 1.
不确定,但您是否尝试在一个核心上生成 1024 个线程?
大多数内存分配器不会return 所有它们的内存到OS。
尝试调用 run()
两次并在第二次检查 RSS before/after。
(也就是说,荒谬的线程数通常不是一个好主意)