临时任务需要个脚本,需要并发,但是因为想偷懒,不想弄复杂的线程池,就直接调用了ThreadPoolExecutor进行操作,出现了一大堆意想不到的问题。

Demon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding:utf-8 -*-

from concurrent.futures import ThreadPoolExecutor, wait


def parallelCreareFile():
with ThreadPoolExecutor(max_workers=100) as pool:
for i in range(100000):
with open(f'{i}.file', 'w') as f:
f.write('x')


if __name__ == '__main__':
parallelCreareFile()

正常来说这个脚本没啥特殊步骤,线程池100个进行写文件也不会有什么瓶颈,但是执行过程中发现内存占用直线上升,到后来可以卡死机器。

明显发生了内存溢出的时间,需要查看到底是哪出了问题。一开始以为是自己的代码出问题了,但是使用最简单的pass语句也会出现内存溢出,那么问题应该是在ThreadPoolExecutor包了。

ThreadPoolExecutor源码

image-20200911172910385

查看源码发现工作队列用的无边队列,那么问题基本定位了,尝试复写使用有界队列进行尝试。

复写方法

1
2
3
4
class RewriteThreadPoolExecutor(ThreadPoolExecutor):
def __init__(self, *args, **kwargs):
super(BoundThreadPoolExecutor, self).__init__(*args, **kwargs)
self._work_queue = Queue(maxsize=5000)

使用复写后的方法进行执行任务没有出现内存泄露的时间。但是出现新的问题

加大max_workers出现新问题

加大max_workers为5000时,出现了

1
libgcc_s.so.1 must be installed for pthread_cancel to work

降低参数值,一切正常。在多个机器上进行尝试加大数值,均出现了该问题。

按照网上的说法是升级GCC,但是依旧出现该问题。最后也没解决,就压到3000执行吧。

TODO

  • 定位libgcc_s.so.1 must be installed for pthread_cancel to work的原因