Subprocess Popen调用Python脚本时stdout为空的原因排查
问题原因与解决方法
核心原因
Python在非终端输出环境(比如被重定向到管道)时,stdout默认采用块缓冲模式,而非终端环境的行缓冲模式。子进程里的print(i)输出会被暂存到内存缓冲区,不会立即写入管道,直到缓冲区填满或进程正常退出才会输出。但你的主进程在5秒后就调用p.terminate()终止了子进程,此时缓冲区里的内容还没来得及写入管道,导致主进程读不到任何输出。
而ls命令的输出逻辑不同,它会直接刷新输出流,不存在缓冲延迟,因此能正常被主进程读取。
解决方法
以下几种方式都能解决这个问题:
给子进程Python命令添加无缓冲参数
在python后加上-u参数,强制让stdout/stderr变为无缓冲/行缓冲模式,确保每次print的内容立即写入管道:cmd = 'python', '-u', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]'子进程中手动刷新输出缓冲区
修改子进程的print语句,添加flush=True参数,强制每次输出后刷新缓冲区:cmd = 'python', '-c', 'import time; [(print(i, flush=True), time.sleep(1)) for i in range(5)]'等待子进程正常完成(替代定时终止)
如果不需要强制5秒终止子进程,可以去掉超时逻辑,改用p.wait()等待子进程执行完毕,同时读取输出(此方式会阻塞主进程直到子进程结束):import os import time import subprocess cmd = 'python', '-c', 'import time; [(print(i), time.sleep(1)) for i in range(5)]' p = subprocess.Popen(cmd, stdout=subprocess.PIPE) os.set_blocking(p.stdout.fileno(), False) while p.poll() is None: line = p.stdout.readline() if len(line): print(line) time.sleep(0.1)
内容的提问来源于stack exchange,提问作者Alexander Soare
相关产品推荐
相关产品推荐

