p = await asyncio.create_subprocess_exec(
'ffmpeg', '-i', src, out,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT)
out, _ = await p.communicate()
用 create_subprocess_exec 调外部工具,输出一多就停住不动,等十几分钟也没有进展,杀掉进程后日志里只有前半段结果,尾部看不到。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。
追下去是这么回事:子进程的标准错误接的是管道,缓冲区写满后它写不进去就阻塞,父进程只在等进程结束没有同时读,两边互相等形成死锁。
「异步子进程管道」改完先别急着全量,挑一台机器放半天,真有问题这段时间就能看出来。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。
处理上按这个顺序:把 stderr 重定向到 STDOUT,合并成一路输出一起读,别分两个管道;起一个协程持续读输出,边读边写日志或者处理;用 communicate 等进程结束,它会同时把两个管道读完再取返回码。
确认没问题再收工,大输出任务能完整跑到结束,返回码为零,日志里内容也是完整的。
