首页 > 解决方案 > 当对象很大时 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:

每次迭代它都会在同一个确切的位置中断。我打印它正在处理的当前主题的名称,它总是在同一行的同一位置中断,然后挂起。我不确定这是否有帮助,但这是附加信息。始终在同一时间断裂。

标签: python-3.xpython-multiprocessing

解决方案


来自多处理指南。

应尽可能避免在进程之间转移大量数据。

multiprocessing.Pool依靠锁定的缓冲区(OS 管道)在工作人员之间分配任务并检索他们的结果。如果将大于缓冲区的对象推入管道,则逻辑可能会挂起。

我建议您将作业转储到文件(pickle例如使用)并将文件名发送到子进程。这样,每个进程都可以独立地检索数据。您不仅可以防止您的逻辑卡住,而且您会注意到速度的提高以及管道成为您设计中的严重瓶颈。


推荐阅读