python-3.x - 当对象很大时 pool.map 冻结
问题描述
我正在使用 pool.map 来填充字典——称为节点。需要明确的是:这个字典是在 pool.map 运行之后填充的,所以在进程之间共享变量不是一个问题。函数返回的所有内容以及字典中的所有内容都是可挑选的。它正在填充本质上是图形的字典。当我深入填充此图表时,程序运行完美无缺。但是在 4 深度:程序似乎没有崩溃,只是冻结了。我在我映射到的函数中设置了打印语句,在它运行的最后,它在程序的最顶部打印语句,然后冻结。这是我调用 pool.map 的方式:
currentNode = startingNode
nodesPopulated = [currentNode]
connections = []
merger = []
pool = Pool(cpu_count())
for currentDepth in range(1, depth):
print('=' * 70)
print("= At depth", currentDepth)
connections = []
for item in nodesPopulated:
if item != None:
if item.isPopulated():
connections +=list(item.getConnections().values())
print("= Current number of connections:",len(connections))
print("= Current number of NodesPopulated in this iteration: ",len(nodesPopulated))
print("= Total number of nodes",len(self.nodes.keys()))
nodesPopulated = pool.map(self.populateTopicNode, connections)
print('\n= Successfully populated another round of nodes')
for node in nodesPopulated:
if node != None:
if item.isPopulated():
self.nodes[node.getTopic().getName()] = node
#self.populatedNodes[node.getTopic().getName()] = True;
print('= Updated self.nodes\n')
pool.close()
pool.join()
print('\nCount = ',len(list(self.nodes.keys())))
return
再一次,我确保返回到 nodesPopulated 的所有内容都是可腌制的。我束手无策,因为运行这个程序 4 深大约需要 2 个小时,没有 pool.map 它可以完美运行,但需要大约 6 个小时。我不想放弃多处理,但我无法弄清楚这一点,而且调试需要很长时间。它在冻结之前打印的最后一件事是'D',它位于 self.populateTopicNode 的顶部。我还认为对象变得太大(self.nodes 和连接)可能是冻结的原因。
注意:我确定这是一个多处理问题,因为我在没有使用 pool.map 的情况下运行了这个确切的代码,并用 for 循环替换了它,它运行完成而没有错误。所以有些东西导致 pool.map 冻结。没有错误消息只是在第一次引用函数参数时挂起。以下是“populateTopicNode”的前几行:
def populateTopicNode(self, node: TopicNode):
print('D')
if(node.isPopulated()):
return None
冻结前在控制台上看到的最后一件事是“D”
它使用大约 1300 mb 的内存挂起。
编辑2:
好的,所以我发现它返回的不仅仅是随机挂起的东西。它返回 None 然后挂起。我不确定为什么,因为很多时候它返回 None 并且工作正常。我还将我的函数包装在一个尝试中,除了查看是否向父级返回异常是否吓坏了,这也不是问题。没有异常被捕获并且它正在运行到它返回的点。它只是在返回后挂起。
编辑3:
每次迭代它都会在同一个确切的位置中断。我打印它正在处理的当前主题的名称,它总是在同一行的同一位置中断,然后挂起。我不确定这是否有帮助,但这是附加信息。始终在同一时间断裂。
解决方案
来自多处理指南。
应尽可能避免在进程之间转移大量数据。
multiprocessing.Pool
依靠锁定的缓冲区(OS 管道)在工作人员之间分配任务并检索他们的结果。如果将大于缓冲区的对象推入管道,则逻辑可能会挂起。
我建议您将作业转储到文件(pickle
例如使用)并将文件名发送到子进程。这样,每个进程都可以独立地检索数据。您不仅可以防止您的逻辑卡住,而且您会注意到速度的提高以及管道成为您设计中的严重瓶颈。
推荐阅读
- c++ - qt项目makfile中的链接包含路径问题
- javascript - jQuery 为具有相同类名的两个嵌套元素触发两次
- reactjs - 浅路由更新路由,但 router.query 不返回最后更新的查询字符串?
- php - 触发 Stripe SCA 重定向以进行身份验证
- ios - 获取 SwiftUI 图像视图的大小
- php - 我无法居中引导 svg 图标
- javascript - 使用纯 JavaScript 将对象数组转换为 CSV
- python - 如何舍入“浮动”对象?
- javascript - 根据 id 删除特定对象,但它从 json 中删除所有对象
- visual-studio - Gulp 错误缺少脚本:在 MVC 项目中构建