我编写了一个脚本,该脚本部署在具有 112 个内核的 HPC 节点中,从而启动 112 个进程,直到完成所需的 400 个进程(node_combinations
是 400 个元组的列表(。相关的代码片段如下:
# Parallel Path Probability Calculation
# =====================================
node_combinations = [(i, j) for i in g.nodes for j in g.nodes]
pool = Pool()
start = datetime.datetime.now()
logging.info("Start time: %s", start)
print("Start time: ", start)
pool.starmap(g._print_probability_path_ij, node_combinations)
end = datetime.datetime.now()
print("End time: ", end)
print("Run time: ", end - start)
logging.info("End time: %s", end)
logging.info("Total run time: %s", start)
pool.close()
pool.join()
我通过运行htop
来跟踪性能并观察以下内容。最初,所有 112 个内核都以 100% 的速度工作。最终,由于某些进程比其他进程短,因此我只剩下较少数量的内核以 100% 的速度工作。最终,所有进程都显示为休眠状态。
我认为问题在于其中一些进程(需要更长的时间,大约 20 个中的 400 个(需要大量内存。当内存不足时,进程进入睡眠状态,由于内存永远不会释放,它们会留在那里,休眠。这些是我的问题:
进程完成后,资源(读内存(是释放还是保持占用状态,直到所有进程完成?换句话说,一旦我只有 20 个内核在工作(因为其他内核已经处理了所有较短的进程(,它们是否可以访问所有内存或仅访问其余进程未使用的内存?
我读到
maxtasksperchild
在这种情况下可能会有所帮助。这将如何运作?如何确定每个孩子的适当任务数是多少?
如果你想知道我为什么要问这个,那是因为在文档中我读到了这个:2.7 版新功能:maxtasksperchild 是工作进程在退出并替换为新的工作进程之前可以完成的任务数,以便释放未使用的资源。默认的 maxtasksperchild 为 None,这意味着工作进程的生存时间与池一样长。
您应该至少保留一个可用于核心操作系统的核心和一个可用于启动脚本的内核;尝试减小池大小。 例如 游泳池(110(
使用 Pool.imap(或 imap_unordered(而不是 Pool.map。这将延迟迭代数据,而不是在开始处理之前将所有数据加载到内存中。
将值设置为 maxtasksperchild 参数。
当您使用多进程池时,将使用 fork(( 系统调用创建子进程。其中每个进程都以当时父进程的内存副本开始。由于在创建池之前加载元组列表,因此池中的进程将具有数据的副本。
这里的答案是通过一种内存分析方法,以便您可以看到内存的去向,何时。