我编写了一个脚本,该脚本部署在具有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%工作。最终,所有进程都显示为睡眠状态。
我相信问题是这些过程中的某些过程(花费更长的时间,约占400个过程中的20个)需要大量内存。当内存不足时,进程将进入睡眠状态,并且由于从不释放内存,因此它们将保持睡眠状态。这些是我的问题:
一个进程完成后,是否释放了资源(读存储器),或者在所有进程完成之前它们仍被占用?换句话说,一旦我只有20个内核在工作(因为其他内核已经处理了所有较短的进程),它们是否有权访问所有内存或仅剩下的内核不使用?
我已阅读到maxtasksperchild
在这种情况下可能会有所帮助。那将如何工作?如何确定每个孩子合适的任务数量?
如果您想知道为什么要问这个问题,那是因为在文档中我读到了这一点: 2.7版中的新增功能:maxtasksperchild是工作进程退出之前可以完成的任务数量,可以替换为新的工作进程,以释放未使用的资源。默认的maxtasksperchild为None,这意味着工作进程将与池一样长。
答案 0 :(得分:0)
您应至少使一个内核可用于核心操作系统,而一个内核可用于启动脚本;尝试减小池的大小。例如泳池(110)
使用Pool.imap(或imap_unordered)代替Pool.map。与开始处理之前将所有数据加载到内存中相比,这将使数据延迟访问。
为maxtasksperchild参数设置一个值。
使用多处理池时,将使用fork()系统调用创建子进程。这些进程中的每一个都以当时父进程的内存副本开始。因为在创建池之前要加载元组列表,所以池中的进程将具有数据副本。
答案here介绍了一种内存分析的方法,因此您可以看到内存的去向,时间。