python - 使用管道时子进程调用未终止

2 投票
3 回答
4409 浏览
提问于 2025-04-16 09:00

我在使用 Python 2.6.5 时遇到了一个奇怪的问题。如果我在网络接口 eth0 关闭的情况下调用

p = subprocess.Popen(["ifup eth0"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()

这个 Python 程序就会卡住。“p.communicate()” 需要花费一分钟或更长时间才能完成。如果接口之前是开启的,程序就能顺利运行。我手动在命令行中测试了“ifup eth0”这条命令,无论是接口开启还是关闭,执行速度都非常快。

如果你有任何想法,能告诉我问题可能出在哪里,我会非常感激。

提前谢谢你

编辑:

根据大家的回答,我尝试了以下几种方法:

p = subprocess.Popen(["ifup", "eth0"], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()

如果接口之前是开启的,脚本运行得很顺利。但是如果接口是关闭的,Python 又会卡住。我还尝试了:

p = subprocess.Popen(["ifup", "eth0"], shell=False)
out, err = p.communicate()

结果一切运行得非常快。因此,这可能确实和死锁有关,正如 funktku 指出的那样。不过,Python 的文档也提到过 python 参考

警告

当使用 stdout=PIPE 和/或 stderr=PIPE 时,如果 子进程生成的输出足够多, 会导致阻塞,等待操作系统的管道缓冲区接受更多 数据。这时请使用 communicate() 来避免。

所以应该不会有死锁。嗯……这是我在命令行运行程序时的详细输出:

1. 情况一,接口 eth0 已经开启:

ifup eth0
Interface eth0 already configured

2. 情况二,之前接口是关闭的:

ifup eth0 
ssh stop/waiting
ssh start/running

所以在接口之前关闭的情况下,ifup 命令会生成两行输出,而在接口开启的情况下只生成一行输出。这是我注意到的唯一区别。但我怀疑这不是问题的根源,因为“ls -ahl”会产生更多的输出行,而且运行得很好。

我还尝试调整了缓冲区大小参数,但没有成功,设置成像 4096 这样的大值也没用。

你有什么想法,可能是什么原因呢?或者这可能是 Python 在处理管道时的一个 bug,或者是 ifup 命令本身的问题?我真的需要使用旧的 os.popen(cmd).read() 吗???

编辑2:

os.popen(cmd).read() 也遇到了同样的问题。你有什么办法可以在命令行测试 ifup 的管道行为吗?

我非常感谢任何提示,提前谢谢你

3 个回答

1
p = subprocess.Popen(["ifup", "eth0"], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()

shell=False 设置为这样,你其实不需要它。

试着运行这段代码,应该可以正常工作。注意看,两个参数是列表中的不同元素。

3

你应该看看subprocess.call方法下的警告。这可能是你遇到问题的原因。

警告

就像Popen.wait()一样,当使用stdout=PIPE和/或stderr=PIPE时,如果子进程生成的输出太多,导致管道被堵住,它会出现死锁的情况,这样就会一直等待操作系统的管道缓冲区接受更多数据。

1

/etc/network/if-up.d/ntpdate 没有正确分离

这就是为什么 read() 会一直等到文件描述符(标准输入/标准输出/标准错误)关闭的原因。你可以分离标准输入/标准错误/标准输出(不要在调用 stdout=subprocess.PIPE 和 Popen 构造函数时添加 stdout)。

撰写回答