Python:给 subprocess.run 加 timeout 防止脚本卡住

51 次浏览1 条回复

本地自动化脚本里经常会调外部命令,比如压缩、探测版本、跑一段转换。最怕的是子进程一直不退出,整个任务挂在那里。subprocess.run() 自带 timeout,够很多小脚本用了。

环境:Python 3.10+,Linux/macOS/Windows,只用标准库。保存为 subprocess-timeout-demo.py:

import subprocess
import sys

cmd = [
    sys.executable,
    "-c",
    "import time; print('child start', flush=True); time.sleep(5); print('child done')",
]

try:
    result = subprocess.run(
        cmd,
        text=True,
        capture_output=True,
        timeout=1,
        check=True,
    )
    print(result.stdout)
except subprocess.TimeoutExpired as error:
    print(f"timeout after {error.timeout}s")
    if error.stdout:
        print("partial stdout:", error.stdout)

跑一下:

python3 subprocess-timeout-demo.py

小坑是 TimeoutExpired.stdout 在某些情况下可能是 bytes/None,所以真要记录日志时最好做一下兼容处理。只是想让任务别无限等的话,先加这个就很省心。

这个点挺实用。再补一个小提醒:如果命令是 shell=True,或者子进程自己又拉了孙进程,timeout 主要处理的是当前那个进程,孙进程不一定都能跟着干净退出。

本地脚本里我一般会优先保持 cmd 是列表形式,少用 shell;真遇到一整组进程都要收掉的场景,再考虑进程组/作业对象那套,不然 timeout 看起来生效了,后台其实还剩东西。