Python中进程池ProcessPoolExecutor如果一直不释放,会有什么弊端?
场景是使用 tornado 写了一个服务,涉及到一些耗 cpu 的计算,使用了concurrent.futures.ProcessPoolExecutor。
那么最佳实践应该是每次请求时初始化一个进程池,还是保持一个全局的进程池?
class MyHandler(BaseHandler):
@coroutine
def post(self, *args, **kwargs):
...
with ProcessPoolExecutor() as process_pool:
fs = [process_pool.submit(job) for job in jobs]
...
还是这样?
class MyHandler(BaseHandler):
process_pool = ProcessPoolExecutor()
@coroutine
def post(self, *args, **kwargs):
...
fs = [self.process_pool.submit(job) for job in jobs]
...
Python中进程池ProcessPoolExecutor如果一直不释放,会有什么弊端?
一般来说每个 ProcessPoolExecutor 默认都会创建和 cpu 核心数相同的进程来执行所有任务,如果你想复用这个进程而不是每次都创建,那么就应该用全局的
其实每次创建进程的开销应该还是挺大的,而且进程启动时在第一次添加任务的时候,所有一个全局进程持也没什么影响
进程池不释放,最直接的弊端就是资源泄露。每个子进程都会占用独立的内存空间(比如Python解释器、加载的模块、全局变量等),如果创建后不关闭,这些内存会一直被占用,即使任务已经完成。在长时间运行的服务或脚本中,这会导致内存使用量不断攀升,最终可能耗尽系统资源,引发 MemoryError 或使系统变慢。
另一个关键问题是文件描述符泄露。每个进程可能会打开文件、网络连接等。如果进程池不关闭,这些资源可能不会被正确清理,导致程序达到系统的文件描述符上限,进而无法打开新的文件或网络连接。
在Windows系统上,这个问题可能更明显,因为 spawn 启动方式会让每个子进程都重新导入主模块,如果模块级代码有副作用(如创建临时文件),可能会引发意外行为。
标准做法是用 with 语句或手动调用 shutdown(wait=True) 来确保清理。比如:
from concurrent.futures import ProcessPoolExecutor
import time
def worker(x):
time.sleep(0.1)
return x * x
# 正确做法:使用 with 语句,执行完毕后自动关闭池
def main():
with ProcessPoolExecutor(max_workers=4) as executor:
futures = [executor.submit(worker, i) for i in range(10)]
results = [f.result() for f in futures]
print(results)
# 退出 with 块后,进程池会自动关闭并等待所有进程结束
if __name__ == '__main__':
main()
如果不方便用 with,也要确保显式关闭:
executor = ProcessPoolExecutor(max_workers=4)
try:
futures = [executor.submit(worker, i) for i in range(10)]
results = [f.result() for f in futures]
print(results)
finally:
executor.shutdown(wait=True) # 等待所有进程结束并释放资源
总之,用完就关,别让进程池变成“僵尸池”。
应该用全局的
ProcessPool 应该全局共享
全局的, 不过我是 java… 线程池的实现里会有空闲时保持少量线程, 忙时再创建的特性, 以减少闲时资源占用.

