【问题标题】:Avoid Deadlock wtih Popen and stdout = PIPE in python在 python 中使用 Popen 和 stdout = PIPE 避免死锁
【发布时间】:2023-03-17 11:00:01
【问题描述】:

我正在使用 Popen 执行一个 shell 脚本。我也在使用 stdout=PIPE 来捕获输出。代码是

pipe = Popen('acbd.sh', shell=True, stdout = PIPE)
while pipe.poll() is None:
        time.sleep(0.5)
text = pipe.communicate()[0]
if pipe.returncode == 0:
    print "File executed"

根据文档,使用带有 stdout = PIPE 的 poll 可能会导致死锁。 communicate() 也可以用来解决这个问题。我在这里使用了communicate()。

我的代码是否也会导致与通信的死锁,还是我使用的通信使用错误?

我在 subprocess.check_output 中也有一个替代项,但我更喜欢使用 Popen 并用相同的方式记录输出。

【问题讨论】:

  • 顺便说一句,不要在这里使用shell=True。您可以在没有它的情况下执行作为 shell 脚本的外部进程。基本上,shell=True 使您的第一行等同于pipe = Popen(['sh', '-c', 'abcd.sh'], stdout=PIPE) - 但如果您的abcd.sh 是可执行的(具有+x 权限和有效的shebang),那么您就不需要需要 @ 987654328@ 被显式调用以运行它,事实上,当您只需要一个时,您会生成 两个 shell(第一个运行 sh -c,第二个由 shebang 调用为abcd.sh)。
  • 另外,请参阅PEP-8 以获取有关 Python 代码格式约定的指导——= 周围的空格在赋值时是正确的,但在传递关键字参数值或在参数列表——所以它是pipe = Popen(...),但stdout=PIPE
  • @CharlesDuffy 感谢您的指导。我猜studout = PIPE 一定是提出论点的正确方式。我会进一步阅读。
  • @CharlesDuffy 如果我给出shell=false 命令,我会收到错误消息。它说“没有这样的文件或目录”
  • 在这种情况下,pipe = Popen(['scriptname', 'arg1', 'arg2'], stdout=PIPE) 是格式。这比尝试使用字符串连接来形成参数要安全得多,因为这意味着有人将$(rm -rf $HOME)(或类似破坏性的东西)潜入正在处理的文件名中不会导致该字符串作为命令运行。

标签: python python-2.7 deadlock popen


【解决方案1】:

是的,你可以死锁,因为这两行:

while pipe.poll() is None:
    time.sleep(0.5)

把它们拿出来;这里不需要他们。 communicate() 将等待子进程按原样关闭其 FD(就像退出时发生的那样);当您自己添加一个循环时,直到该循环完成后才阅读,那么您的程序可能会无限期地卡住尝试写入无法写入的内容,直到 communicate() 导致另一方开始读取的管道。


作为背景:write() 调用的 POSIX 规范不保证在 FIFO 阻塞之前可以写入的数据量,或者该数据量将保持一致 在给定的系统中——因此,安全的做法是假设对 FIFO 的任何写入总是被允许阻塞,除非有读取器在积极地使用该数据。

【讨论】:

  • 我使用 while 循环和语句的动机是代码在流程完成之前不应继续前进。如果我使用text = pipe.communicate()[0],这会等到我的过程完成并将shell脚本输出保存在文本变量中吗?
  • 是的,pipe.communicate() 将等到该过程完成。是的,text = pipe.communicate()[0] 会将已完成进程的标准输出保存在名为 text 的变量中。
  • 根据文档,“while pipe.poll() is None...”用于在进程运行时执行其他操作。但是为什么这里会陷入死循环呢?
猜你喜欢
  • 1970-01-01
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 2017-12-17
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多