Python 多处理队列使代码在处理大数据时挂起

2023-12-30

我正在使用 python 的多重处理来分析一些大文本。经过几天尝试找出我的代码挂起的原因(即进程没有结束)后,我能够使用以下简单代码重新创建问题:

import multiprocessing as mp

for y in range(65500, 65600):
    print(y)

    def func(output):

         output.put("a"*y)

    if __name__ == "__main__":

        output = mp.Queue()

        process = mp.Process(target = func, args = (output,))

        process.start()

        process.join()

正如您所看到的,如果要放入队列的项目太大,进程就会挂起。 如果我之后编写更多代码,它不会冻结output.put()它会运行,但该过程永远不会停止。

当字符串达到 65500 个字符时,这种情况就会开始发生,具体取决于您的解释器,它可能会有所不同。

我知道mp.Queue has a maxsize参数,但做了一些搜索,我发现它与队列的项目数量大小有关,而不是项目本身的大小。

有没有解决的办法? 我需要在原始代码中放入队列的数据非常非常大......


您的队列已满,没有消费者可以清空它。

从定义Queue.put https://docs.python.org/2/library/multiprocessing.html#multiprocessing.Queue.put:

如果可选参数 block 为 True(默认值)且超时为 None(默认值),则根据需要进行阻止,直到有空闲槽可用。

假设生产者和消费者之间不存在死锁(并且假设您的原始代码确实有消费者,因为您的示例没有),最终生产者应该被解锁并终止。检查您的消费者的代码(或将其添加到问题中,以便我们查看)


Update

这不是问题,因为队列尚未指定 maxsize,因此 put 应该会成功,直到内存耗尽。

这不是队列的行为。正如本文中详细阐述的ticket https://bugs.python.org/issue8426,这里阻塞的部分不是队列本身,而是底层的管道。从链接的资源(“[]”之间的插入是我的):

队列的工作方式如下: - 当你调用queue.put(data)时,数据被添加到双端队列中,双端队列可以永远增长和收缩 - 然后一个线程从双端队列中弹出元素,并发送它们,以便其他进程可以通过管道或 Unix 套接字(通过套接字对创建)接收它们。但是,这是重要的一点,管道和 unix 套接字的容量都是有限的(过去是 4k - 页大小 - 在旧版 Linux 内核上的管道,现在是 64k,unix 套接字在 64k-120k 之间,具体取决于可调节的 systcls) 。 - 当你执行queue.get()时,你只需在管道/套接字上进行读取

[..]当大小[变得太大]时,写入线程会在写入系统调用上阻塞。 并且由于在将项目出列之前执行了连接[注意:这是您的process.join],你只是死锁,因为连接等待发送线程完成,并且由于管道/套接字已满而写入无法完成! 如果您在等待提交者进程之前将项目出队,则一切正常。


Update 2

我明白。但我实际上没有消费者(如果是我想的那样),只有当进程完成将其放入队列中时,我才会从队列中获取结果。

是的,这就是问题所在。这multiprocessing.Queue不是储存容器。您应该专门使用它来在“生产者”(生成进入队列的数据的进程)和“消费者”(“使用”该数据的进程)之间传递数据。正如您现在所知,将数据留在那里是一个坏主意。

如果我什至无法先将其放入队列中,如何才能从队列中获取该项目?

put and get如果数据填满了管道,就隐藏了将数据放在一起的问题,因此您只需在“主”进程中设置一个循环即可get将项目移出队列,例如将它们附加到列表中。该列表位于主进程的内存空间中,不会堵塞管道。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 多处理队列使代码在处理大数据时挂起 的相关文章

随机推荐