使用subprocess.Popen调用python脚本并刷新数据

Vik*_*tor 11 python subprocess pipe

好的,所以我已经看到了十几个这样的线程,但是没有一个给出了完整的答案,我到目前为止所做的一切都不适合我.

1)不断输出一些数据并刷新它的脚本:

import time
import sys

if __name__ == '__main__':
    for i in range(5):
        print i,
        sys.stdout.flush()
        time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

2)用Popen调用第一个脚本的脚本,应该逐个打印数字但由于某种原因没有,并且一次打印它们:

import sys
import subprocess

if __name__ == '__main__':
    process = subprocess.Popen(['python', 'flush.py'], stdout = subprocess.PIPE )
    for line in iter(process.stdout.readline, ''):
        print line,
        sys.stdout.flush()
Run Code Online (Sandbox Code Playgroud)

我有点困惑的第一件事就是在第一个脚本中,如果你删除了flush它会在一行中返回输出O_O ...我很确定这是因为time.sleep但仍然有点预期它会像一个标准输出不断返回值0,1,2,3,4但不是全部在一起,当然冲洗解决它,但只是奇怪,至少对我来说......

主要问题: 第二个脚本是不是一个一个地返回数字,而是一次性返回一个输出.....我需要的是看到数字逐个弹出...

我读到某个地方,它没有返回EOF,Popen等待关闭管道,这就是为什么它运行到最后......

那我该怎么办或接下来尝试一下呢? 提前致谢.

jfs*_*jfs 11

正如@Warren Weckesser的评论所说,你的问题与缓冲问题无关.

.readline()在父进程中,在读取换行符或达到EOF之前不会返回.您的子进程根本不打印任何换行符,因此在子进程结束之前,父进程不会打印任何内容.

最小修复只是删除print i,子脚本末尾的逗号.

这也有效:

#!/usr/bin/env python
import sys
from subprocess import Popen, PIPE

p = Popen([sys.executable or 'python',
           '-u', # unbuffer stdout (or make it line-buffered on Python 3)
           '-c',
           """
import time

for i in range(5):
    print(i) # <-- no comma i.e., each number is on its own line
    time.sleep(1)
"""], stdout=PIPE, bufsize=1)
for line in iter(p.stdout.readline, b''):
    print(int(line)**2)
Run Code Online (Sandbox Code Playgroud)

例:

 $ python parent.py
 0
 1
 4
 9
 16
Run Code Online (Sandbox Code Playgroud)

数字每秒打印一次,无需等待子进程结束.

如果您不想更改子脚本,那么您应该readline()在空格而不是换行符处使用该句点,例如:

#!/usr/bin/env python
import sys
from subprocess import Popen, PIPE

p = Popen(['python2', 'child.py'], stdout=PIPE, bufsize=0)
for token in generate_tokens(p.stdout):
    print(int(token))
Run Code Online (Sandbox Code Playgroud)

其中generate_tokens()产生空白分隔的标记:

def generate_tokens(pipe):
    buf = []
    while True:
        b = pipe.read(1) # read one byte
        if not b: # EOF
            pipe.close()
            if buf:
                yield b''.join(buf)
            return
        elif not b.isspace(): # grow token
            buf.append(b)
        elif buf: # full token read
            yield b''.join(buf)
            buf = []
Run Code Online (Sandbox Code Playgroud)

它还会在孩子打印后立即打印整数.