asyncio.create_subprocess_exec() 不能直接传字符串命令,因为它直连 execve 系统调用、不经过 shell 解析,必须传入程序名与分离参数列表(如 ["ls", "-l"]),否则会因找不到名为 "ls -l" 的可执行文件而报 FileNotFoundError。
asyncio.create_subprocess_exec() 为什么不能直接传字符串命令
因为
是“直连操作系统 execve 系统调用”的封装,它不经过 shell 解析器。你传进去的必须是可执行程序名 + 分离的参数列表,比如
,而不是
。传字符串会报
——它试图找一个叫
的可执行文件,当然不存在。
常见错误现象:
误写成
→ 报错
在 Windows 上传路径含空格但没加引号(如
)→ 找不到文件
正确做法是手动拆解命令:
如果真需要 shell 功能(通配符、管道、变量展开),该用
,而不是硬塞字符串进
。
立即学习
“
Python免费学习笔记(深入)
”;
stdin/stdout/stderr 参数怎么配才不卡死
默认情况下,
/
/
都是
,即继承父进程的对应流(通常是终端)。这在后台异步任务里极易导致阻塞或不可控输出。要捕获输出,必须显式设为
;要避免子进程因 stdin 未关闭而挂起,通常得设
或主动
。
关键点:
只要用了
,就必须调用
(或分别读
+
),否则子进程可能永远等不到 EOF
参数控制缓冲区大小(默认 64KiB),大输出(如
)不设容易内存爆掉
不要混用
和
,前者会消费缓冲区,后者会再读一次,导致丢数据或 hang
示例(安全捕获):
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
和 subprocess.run() 的核心区别在哪
最根本的是:前者是异步非阻塞,后者是同步阻塞。你在协程里用
性能与场景差异:
并发多个命令?
+
天然支持;
只能串行或开线程池(额外管理开销)
需要实时流式处理输出(如 tail -f 日志)?只有
能边读边处理;
必须等命令结束才拿到全部 stdout
超时控制更精细:
可以配合
做细粒度 timeout;
是粗暴 kill
别被“简单”误导:用
写脚本没问题,但在 FastAPI/Quart/ASGI 应用或长周期监控服务里混用,就是隐性性能地雷。
Windows 下路径和编码问题怎么绕过去
Windows 的 cmd/powershell 默认编码不是 UTF-8,且路径分隔符、空格、驱动器盘符都容易出事。这不是 asyncio 的锅,但会集中暴露在
场景里。
实操建议:
避免依赖系统 shell 工具,优先用 Python 内置模块(
替代
)
调用外部程序时,用绝对路径并确保路径中无中文或特殊字符;含空格路径必须作为独立参数传,不要拼接
如果必须处理中文路径或输出,显式指定
在
里,别依赖系统 locale
PowerShell 命令一律走
,并加
前缀,
不认 PowerShell 语法
容易被忽略的一点:Windows 上某些程序(如
)退出码语义和 Unix 完全不同,
不一定代表成功,得查文档看具体含义。
create_subprocess_exec()["ls", "-l", "/tmp"]"ls -l /tmp"FileNotFoundError: [Errno 2] No such file or directory"ls -l /tmp"await asyncio.create_subprocess_exec("ping -c 1 google.com")["C:\Program Files\nodejs\node.exe", "--version"]proc = await asyncio.create_subprocess_exec(
"ping", "-c", "1", "google.com",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
create_subprocess_shell()execstdinstdoutstderrNoneasyncio.subprocess.PIPEstdin=asyncio.subprocess.DEVNULLproc.stdin.close()PIPEproc.communicate()stdout.read()stderr.read()limittar -czproc.stdout.readline()proc.communicate()proc = await asyncio.create_subprocess_exec(
"find", "/", "-name", "*.py", "-print0",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL,
limit=1024*1024 # 1MB 缓冲
)
stdout, _ = await proc.communicate()
subprocess.run(),整个事件循环就停了,哪怕只等 1 秒,所有其他任务(网络请求、定时器、UI 更新)全卡住。create_subprocess_exec()asyncio.gather()run()execrun()proc.wait()asyncio.wait_for()run(timeout=...)run()create_subprocess_exec()shutil.copytreexcopyencoding="utf-8"proc.stdout.decode()create_subprocess_shell()-ExecutionPolicy Bypass -Commandexecrobocopyproc.returncode == 0