subprocess.Popen的stdin.buffer / stdout永远不会刷新

时间:2019-08-27 11:53:23

标签: python python-3.x linux subprocess

我正在编写一个python守护程序(使用python 3.7),该守护程序不断检查stdin上的数据是否可用(使用select)并对其进行处理。数据可以包含非Unicode字符,因此守护程序需要从sys.stdin.buffer而不是sys.stdin读取。

该程序实际上有效。但是我正在使用第二个python脚本为该程序编写功能测试,该脚本以subprocess.Popen启动守护程序,并将数据发送到stdin并从其stdout读取。由于某些原因,该部分不起作用。 proc.readline()会永远阻塞,有些proc.stdin.write永远不会到达子进程。

为简单起见,我有2个小脚本来说明问题。 目前,问题在于test.py中的第一个readline()调用正在阻塞并且永不返回,而test2.py已经向stdout写了整行。

# test.py
from subprocess import Popen, PIPE, TimeoutExpired
import time
import select

proc = Popen(["python", "test1.py"], stdin=PIPE, stdout=PIPE,
             bufsize=0)

print("Writing")
proc.stdin.write("blablabla\n".encode('utf-8'))
time.sleep(2)
output = proc.stdout.readline()
print("Result")
print(output)
print("Writing")
proc.stdin.write("zxczxczxczxc\n".encode('utf-8'))
time.sleep(2)
output = proc.stdout.readline()
print("Result")
print(output)
proc.terminate()
print(proc.stdout.read())
#test1.py
import select
import signal
import sys
import logging
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
log = logging.getLogger()

STOP = False


def stop(frame, signal):
    global STOP
    STOP = False


signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGINT, stop)


def input_available():
    """Check if data is available on stdin."""
    data_available = select.select([sys.stdin], [], [], 0)
    return sys.stdin in data_available[0]

data = ""
while not STOP:
    if input_available():
        char = sys.stdin.buffer.read(1)
        try:
            char = char.decode('utf-8')
            data += char
        except UnicodeDecodeError:
            char = None
            print("skipping char")
        if char == '\n':
            s = f"Got line {data}"
            print(s)
            log.debug(s)
            data = ""
        sys.stdout.flush()

编辑 从@ charles-duffy的赞誉中,我用strace运行了它。子程序中的程序似乎在read调用上受阻? 这是strace输出的最后一位:

write(1, "Writing\n", 8Writing
)                = 8
write(4, "blablabla\n", 10)             = 10
select(0, NULL, NULL, NULL, {tv_sec=2, tv_usec=0}) = 0 (Timeout)
read(5,

0 个答案:

没有答案