多处理返回“打开的文件太多”,但使用 `with...as` 修复它。为啥?

Posted

技术标签:

【中文标题】多处理返回“打开的文件太多”,但使用 `with...as` 修复它。为啥?【英文标题】:multiprocessing returns "too many open files" but using `with...as` fixes it. Why?多处理返回“打开的文件太多”,但使用 `with...as` 修复它。为什么? 【发布时间】:2018-01-21 18:56:02 【问题描述】:

我使用this answer 在 Linux 机器上运行 Python 中的多处理并行命令。

我的代码做了类似的事情:

import multiprocessing
import logging

def cycle(offset):
    # Do stuff

def run():
    for nprocess in process_per_cycle:
        logger.info("Start cycle with %d processes", nprocess)
        offsets = list(range(nprocess))
        pool = multiprocessing.Pool(nprocess)
        pool.map(cycle, offsets)

但我收到此错误:OSError: [Errno 24] Too many open files 因此,代码打开了太多的文件描述符,即:它启动了太多的进程而没有终止它们。

我修复了它,用这些行替换了最后两行:

    with multiprocessing.Pool(nprocess) as pool:
        pool.map(cycle, offsets)

但我不知道这些行修复它的确切原因。

with 下面发生了什么?

【问题讨论】:

这里是source code每个进程正在调用self.terminate() with 版本在pool.map() 返回后隐式调用pool.close()。根据文档,“防止更多任务被提交到池中。所有任务完成后,工作进程将退出”。这可能会导致每个任务已打开的打开文件被关闭。 我错了,还是@COLDSPEED 确实回答了这个问题,现在它被删除了?我无法深入阅读它,但我想......但现在它已经消失了......有人知道为什么这个问题被否决了吗? 嗨@cᴏʟᴅsᴘᴇᴇᴅ ...对此有任何提示吗? @nephewtom 我删除了它,因为我认为它对任何人都没有帮助。我现在已经取消删除了。 【参考方案1】:

您正在循环中创建新进程,然后在完成后忘记关闭它们。结果,您有太多打开的进程。这是个坏主意。

您可以使用自动调用pool.terminate 的上下文管理器来解决此问题,或者您自己手动调用pool.terminate。或者,你为什么不在循环外创建一个池一次,然后将任务发送到里面的进程?

pool = multiprocessing.Pool(nprocess) # initialise your pool
for nprocess in process_per_cycle:
    ...       
    pool.map(cycle, offsets) # delegate work inside your loop

pool.close() # shut down the pool

有关更多信息,您可以仔细阅读multiprocessing.Pool 文档。

【讨论】:

手动调用pool.terminate 可能是这里要做的事情。我无法在外面创建池,因为我想在每次迭代时更改它。因此,在每一个中,衍生进程的数量都在增加。例如,如果 process_per_cycle 为 [2, 4, 8],则每次迭代将产生 2、4 和 8 个进程。 @nephewtom 是的,如果您不能使用上下文管理器,那将是另一种选择。 @nephewtom 我解释了原因...因为with 会在您完成后自动关闭进程池。 为什么在这种情况下操作系统会将进程视为文件? @Sledge 创建进程时必须明确销毁它,除非它是守护进程。【参考方案2】:

它是上下文管理器。使用 with 可确保您正确打开和关闭文件。要详细了解这一点,我推荐这篇文章https://jeffknupp.com/blog/2016/03/07/python-with-context-managers/

【讨论】:

很明显它是一个上下文管理器。但是为什么在这里使用它会导致它起作用呢? 你可以看看this的解释。【参考方案3】:

当您使用 numpy.load 时也会发生这种情况,请确保也关闭这些文件,或者避免使用它并使用 pickle 或 torch.save torch.load 等。

【讨论】:

【参考方案4】:

我已经在终止和关闭池,但是文件描述符的数量有限制,我将我的 ulimit 从 1024 更改为 4096 并且它起作用了。流程如下:

检查:

ulimit -n

我将它更新为 4096 并且可以正常工作。

ulimit -n 4096

【讨论】:

以上是关于多处理返回“打开的文件太多”,但使用 `with...as` 修复它。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

延迟打开的文件导致“打开的文件太多”

Python 子进程:打开的文件太多

错误:EMFILE:打开的文件太多 - React Native CLI

Laravel with() 急切加载返回空数据

Python基础知识

节点和错误:EMFILE,打开的文件太多