Python 中的 Broken Pipe 错误

2024 年 8 月 29 日 | 阅读 3 分钟

如今,Python 被认为是一种成熟的编程语言,因其简洁易读的语法而广受数据科学家和人工智能(AI)工程师的欢迎。除此之外,该编程语言中模糊的错误信息常常让新程序员在调试时抓耳挠腮。

在接下来的教程中,我们将讨论 [Errno 32] Broken pipe(管道破裂),这是我们在与文件系统交互时经常看到的著名错误消息。我们还将了解其原因,以及避免和修复代码中该错误的方法。

Python 中“[Errno 32] Broken pipe”的原因是什么?

"Broken pipe" 通常被认为是一个 IOErrorInput/Output Error,输入/输出错误),它发生在 Linux 系统级别。它通常在读写文件时,或者换句话说,在执行文件输入/输出或网络输入/输出(通过套接字)时引发。

对应的 Linux 系统错误是 EPIPE,摘自 GNU libc 错误代码

宏:int EPIPE

"Broken pipe."(管道破裂。)没有进程从管道的另一端读取。所有引发错误代码的库函数还会产生一个 SIGPIPE 信号;如果该信号未被处理或阻塞,它将终止程序。因此,直到程序处理或阻塞了 SIGPIPE,否则永远不会实际显示 EPIPE

从上面的陈述可以得出结论,发送 SIGPIPE 信号的系统导致了 [Errno 32] Broken pipe 错误,这是 Linux 的一种进程间通信机制。

例如,Linux 系统内部使用另一个名为 SIGINT 的信号。在 Linux 中,命令 Ctrl+C 将发送 SIGINT 信号以结束进程,或者我们可以使用 kill 命令达到相同的效果。

Python 默认不会忽略 SIGPIPE。但是,它会将该信号转换为一个异常,并在每次收到 SIGPIPE 时引发一个错误 - IOError: [Errno 32] Broken pipe

在 Linux 终端中管道输出结果时发生管道破裂错误

每当我们在尝试将 Python 脚本的输出通过管道传递给另一个程序时遇到 [Errno 32] Broken pipe 错误,如下面的示例所示

示例

说明

上面的管道语法将创建一个向上游发送数据的进程和一个下游读取数据的进程。当下游不再需要读取上游数据时,它将向该上游进程发送 SIGPIPE 信号。

下游何时不再需要读取上游数据?让我们用一个例子来理解。示例中的 head 命令只需要读取足够的行来告知上游我们不再需要读取它,然后它将向该上游进程发送 SIGPIPE 信号。

每当上游进程是 Python 程序时,就会发生像 IOError: [Errno 32] Broken pipe 这样的错误。

如何避免管道破裂错误?

如果我们不关心正确捕获 SIGPIPE,并且希望快速运行,请将以下代码片段插入到 Python 程序的顶部。

语法

说明

在上面的代码片段中,我们将 SIGPIPE 信号重定向到系统通常忽略的默认 SIG_DFL

但是,建议参阅 Python 信号库的文档,其中警告不要这样处理 SIGPIPE。

正确捕获 IOError 以避免管道破裂错误

由于管道破裂错误是 IOError,我们可以放置一个 try/catch 块来捕获它,如下面的代码片段所示。

语法

说明

在上面的代码片段中,我们导入了 sys 和 errno 模块,并放置了一个 try/catch 块来捕获引发的异常并对其进行处理。

多进程程序中管道破裂错误的可能解决方案

在利用工作进程来加快处理速度和利用多核 CPU 的程序中,我们可以尝试减少工作进程的数量,以检查错误是否仍然存在。

大量的工作进程在尝试控制系统资源或写入磁盘的权限时可能会相互冲突。