【发布时间】:2020-02-28 17:30:51
【问题描述】:
我正在处理多个数据集(使用自定义 python 对象封装并在磁盘上序列化),其中包含一系列操作,每个操作大约需要 10/15 秒。我已经将这些操作封装在一个进程上,我正在调用 160 个进程来进行调度。
我设置了Semaphore(6),因为我有一个 8 核 CPU。
问题是在进程 80 左右,RAM 已满,Swap 也已满,系统完全没有响应。
我也努力使用垃圾收集器,但没有任何区别。
它开始正常运行,当时间过去时,系统完全冻结。这是崩溃前htop 的屏幕截图:
Swap is at 5GB but it gets at 8GB before crash
我的系统是: - Ubuntu 18.04 LTS - i7 2600 4 核(8 线程) - GTX 1060 3GB - 内存 DDR3 8GB
代码如下:
import multiprocessing as mp
import sys
import time
from pathlib import Path
import gc
def main():
all_args_list = load_datasets()
processes = []
queue_res = mp.Queue()
cpu_lim = mp.Semaphore(mp.cpu_count() - 2) # Use 6 of my 8 cores
for i, some_args in enumerate(all_args_list):
p = mp.Process(target=process_routine, args=(some_args, queue_res, cpu_lim))
processes.append(p)
for process in processes:
process.start()
for process in processes:
process.join()
results = [queue_res.get() for p in processes]
save(results)
def process_routine(some_args, queue_obj, cpu_lim):
cpu_lim.acquire()
# Do my operations ....
process_result_dict = my_operations(some_args)
# Save process result
res_obj.put(process_result_dict)
gc.collect()
cpu_lim.release()
if __name__ == '__main__':
main()
我应该如何进行以防止 python 劫持所有内存? 为什么 RAM 使用量会随着时间的推移而增加?垃圾收集器不应该收集旧对象吗?
感谢您的宝贵时间!
编辑
我将多个进程更改为一个池。问题是现在它只单独运行每个进程,使用apply_async() 或apply():
pool = mp.Pool(processes=mp.cpu_count())
results = [pool.apply_async(process_routine, args=(my_args,)) for id, my_args in enumerate(datasets)]
【问题讨论】:
-
是的,消耗所有系统资源通常会降低您的计算机响应速度。问题是如何减少资源使用?如果他们都同时工作,那么 180 个 procs 是一大堆。
-
在大多数情况下,您希望池大小等于 CPU 数量。
-
@jordanm,是的,问题是为什么交换和内存耗尽(不应该 gc 清理旧对象)以及如何防止它完全系统崩溃
-
如果您使用的是
Pool,请去掉Semaphore,并将池的大小显式设置为mp.cpu_count() - 2。apply预计单独运行;apply_async不是,但我们不知道您为每个任务做了多少实际工作;如果它很小,并且序列化的参数很昂贵,那将消除您所有的节省。 -
至于 gc 不工作:分叉时的 GC 比不 GC 更糟糕;它触及了大部分引用计数,导致大部分写时复制内存被立即复制。我建议changing your start method to
'forkserver',删除gc.collect,如果这还不够,设置maxtasksperchild=SOMENUMBER,以便间歇性收集子进程并从头开始(这是确保释放所有内存的唯一方法) .
标签: python python-multiprocessing python-multithreading