Python2.x subprocess.Popen 的 Broken pipe 解决方法

考虑如下代码:

#!/usr/bin/env python
p1 = Popen(["cat", "somebigfile"], stdout = PIPE)
p2 = Popen(["head"], stdin = p1.stdout, stdout = PIPE)
print p2.communicate()[0]

会出现

cat: write error: Broken pipe

原因是在Unix-like系统中,Python启动就会SIG_IGN掉SIG_PIPE,致使cat获取不了SIG_PIPE信号,还向已关闭的管道写入。很久之前就有人提出这个BUG了,这个BUG在Python 3.x已经修复,但是一直没有在Python 2.x实现。

解决方法如下:
1. 下载对应版本的Python源码,找到Lib\subprocess.py(我发现2.6.x的跟2.7.x的就不同)
2. 把该文件放到项目文件夹,改名为sub.py
3. 作如下改动:

--- /usr/lib/python2.6/subprocess.py    2010-04-16 21:58:41.000000000 +0800
+++ sub.py      2011-08-26 17:45:57.576284992 +0800
@@ -429,7 +429,7 @@
     import fcntl
     import pickle

-__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"]
+__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError", "_eintr_retry_call"]

try:
     MAXFD = os.sysconf("SC_OPEN_MAX")

4. 新建new_subprocess.py, 建立Popen_new类,继承原来subprocess的Popen,并把sub.py里面Popen类的POSIX版本的_execute_child方法copy过来。

5. 在

if cwd is not None:
    os.chdir(cwd)

后面加上如下代码:

import signal
signals = ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ')
for sig in signals:
    if hasattr(signal, sig):
        signal.signal(getattr(signal, sig), signal.SIG_DFL)

(此处有一个示例,Python 2.6.5版本的)

6. 在项目里

from new_subprocess import Popen_new as Popen

即可

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。