Python 的默认 IO 没有非阻塞 (Non-blocking) 的功能,默认情况下,以任何方式调用
read
,都可能会被阻塞。
场景描述
假设我们现在需要通过 subprocess 调用一个子程序比如 aria2c, 然后需要实时分析它的 stdout 内容。
那么问题就来了:
import timeimport shleximport subprocessfrom subprocess import PIPEcmd = shlex.split(\"ria2c -x16 \'http://host/file.zip\'\", stdout=PIPE)aria2c = subprocess.Popen(cmd, capture_output=True, text=True, encoding=\'utf-8\')while aria2c.poll() is None: # is runningline = aria2c.stdout.readline() # blocking# waittime.sleep(1)
解决办法
- 使用新线程去调用 read() 并保存到一个 buffer 中,主线程直接读 buffer。
- 开销太大
- 使用标准库 select 检查是否可读,比较优雅。
- 使用 fcntl 为 stdout 设置 O_NONBLOCK 标志
参考
- Non blocking reading from a subprocess output stream in Python
- Pure-Python non-blocking IO and background IO functions
- select — Waiting for I/O completion