ThreadPoolExecutor中的#jo;' .join()吃内存

时间:2017-10-25 05:59:11

标签: python multithreading memory-leaks

尝试这样的代码:

import gc
import random
from concurrent.futures import ThreadPoolExecutor

zen = "Special cases aren't special enough to break the rules. "


def abc(length: int):
    msg = ''.join(random.sample(zen, length))
    print(msg)
    del msg


if __name__ == '__main__':
    pool = ThreadPoolExecutor(max_workers=8)
    while True:
        for x in range(256):
            pool.submit(abc, random.randint(2, 6))
        print('===================================================')
        gc.collect()

如果没有ThreadPoolExecutor运行代码可能需要大约8MB,使用str()代替' .join()大约需要30MB。但是这段代码不加限制地吃RAM。我认为它是由random.sample或其他东西引起的,但它证明了ThreadPoolExecutor中的' .join()会导致这个问题。

让我感到困惑,因为没有相互导入的模块(仅限zen),& del或Gc都没有工作:(

ps:请注意无限循环不是问题。当你运行类似的东西时:

while True:
    print(1234567)

内存使用率将保持在某一行(上面的代码可能不会超过1MB?)。顶部的代码没有增加的列表或字典,&变量已经在模块的末尾。因此,当我认为线程完成时应该清理它,显然不是。

pss:让我们这样说:问题的原因是' .join()不会被回收。好像我们这样改变了abc模块:

tmp = random.sample(zen, length)
msg = ''.join(tmp)
print(msg[:8])
del msg, tmp

Gc有效运行,使用量保持在26MB左右。

因此,在使用' .join()或python语言时,我错过了一些错误吗?

1 个答案:

答案 0 :(得分:0)

当您运行没有线程的代码时,每个语句将完全执行,这意味着gc.collect()将在内循环结束后被调用。

但是,当您使用线程执行代码时,将在最新线程结束之前调用一个新线程,因此新线程的数量将迅速增加,并且由于对线程数量没有限制,因此您拥有的线程数将超过您的CPU可以处理导致线程堆积的情况。