【问题标题】:Subprocess popen: Why do all writes happen at once in child process?子进程popen:为什么所有写入都在子进程中同时发生?
【发布时间】:2016-04-29 16:28:31
【问题描述】:

我有两个脚本,一个控制另一个并通过标准输入与它通信。父脚本:

import subprocess
import time

p = subprocess.Popen(['python','read_from_stdin.py'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)

for i in range(0,10):
    p.stdin.write(str(i))
    p.stdin.write('\r\n') # \n is not sufficient on Windows
    p.stdin.flush()
    print i
    time.sleep(1)

p.stdin.close()

子脚本(称为“read_from_stdin.py”):

import sys
import datetime

with open(datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.txt','w') as f:

    for line in sys.stdin:
        f.write(datetime.datetime.now().isoformat() + ' ' + line)

在由子脚本创建的文件中,所有输入都具有相同的时间戳,尽管父脚本相隔一秒写入,并且尽管使用了 flush()。

【问题讨论】:

    标签: python subprocess stdin popen


    【解决方案1】:

    编辑:根据下面 Karoly Horvath 的评论,它不是等待 EOF,而是有缓冲。下面的不同子脚本确实按预期工作。

    我在这个主题上发现了这个问题:How do you read from stdin in Python?

    一个公平的答案是:

    别人提出的答案:

    for line in sys.stdin:
      print line
    

    非常简单和pythonic,但必须注意脚本将 等到 EOF 再开始迭代输入行

    这个子脚本的行为符合预期:

    import sys
    import datetime
    
    with open(datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.txt','w') as f:
    
        line = sys.stdin.readline()
        while line:
            f.write(datetime.datetime.now().isoformat() + ' ' + line)
            line = sys.stdin.readline()
    
        f.write('Finished')
    

    【讨论】:

    • 只是想发帖 :) stackoverflow.com/questions/8416586/turn-off-buffering等待 EOF,但有 缓冲。请更新您的答案。
    • @KarolyHorvath:它不等待 EOF 是正确的,但您链接的问题是不相关的(修复 grep --line-buffered 在这里不起作用 - OP 已经调用 p.stdin.flush() )。问题是 Python 2 中带有for line in sys.stdin 的预读错误。解决方法是:for line in iter(sys.stdin.readline, '')
    • @KarolyHorvath :我看到了。该解决方案有效,但答案中没有关于实际原因的指示(CPython 2 中的错误)
    • 你现在看到了。是的,这是一个错误。
    • @KarolyHorvath:如果您是在暗示我在您发表评论之前没有看到它或者没有理解它,那么您就错了。看看my answers in the subprocess tag。如果您希望我收到有关您的 cmets 的通知,请使用 @username 语法。
    【解决方案2】:

    它是the read-ahead bug in Python 2for line in sys.stdin: 在其内部缓冲区已满之前不会产生任何东西。使用for line in iter(sys.stdin.readline, ''): 来解决它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-15
      • 2018-12-05
      • 1970-01-01
      • 2016-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多