【问题标题】:''.join() in ThreadPoolExecutor eat memory''.join() in ThreadPoolExecutor 吃内存
【发布时间】:2018-04-06 02:29:35
【问题描述】:

试试这样的代码:

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?)。顶部的代码没有递增的列表或字典,并且变量在模块末尾被 del 。所以当我认为线程完成时应该清理它,这显然不是。

pss:我们这样说:问题的原因是''.join()中的任何东西都不会被回收。就好像我们这样改变 abc 模块:

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

Gc 工作效率高,使用量保持在 26MB 左右。

那么我在使用 ''.join() 时是否遗漏了什么或者 python 语言存在错误?

【问题讨论】:

  • 但是这里有一个无限循环。你的程序永远不会结束。由于您没有得到submit 的结果,因此池会越来越大。
  • 你的 while 循环永远不会中断。显然,它将继续增长。
  • 抱歉没有说清楚。当您使用单线程或没有''.join() 运行时,即使使用无限循环,内存使用量也会保持在某一行以下,例如8MB 或更多。它不会不会(重要声明 3 次)增长到数百 MB 甚至更多(4096 个线程的类似示例会占用 13GB RAM)。只有'循环让它成长对我来说没有意义兄弟。

标签: python multithreading memory-leaks


【解决方案1】:

当你在没有线程的情况下运行代码时,每个语句都会完全执行,我的意思是gc.collect()将在内循环结束后被调用。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    相关资源
    最近更新 更多