使用asyncio.subprocess调用外部Python文件时遇ConnectionResetError求助
问题:使用asyncio.subprocess运行外部命令时抛出ConnectionResetError
我在尝试用asyncio.subprocess模块运行外部Python文件时遇到了ConnectionResetError异常,以下是我的代码:
import asyncio async def external(): writing_process=await asyncio.create_subprocess_shell("pwd", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd="/home/user1/folder1") print(await writing_process.stdout.read()) writing_process.stdin.writelines([b"python test.py"]) await writing_process.stdin.drain() print(await writing_process.stdout.read()) asyncio.run(run_outer_py_file())
运行后输出如下:
b'/home/bykov/nra_banks\n' --------------------------------------------------------------------------- ConnectionResetError Traceback (most recent call last) <ipython-input-9-67bbc190049c> in async-def-wrapper() <ipython-input-9-67bbc190049c> in external() 11 print(await writing_process.stdout.read()) 12 await external() ~/anaconda3/lib/python3.7/asyncio/streams.py in drain(self) 346 # would not see an error when the socket is closed. 347 await sleep(0, loop=self._loop) --> 348 await self._protocol._drain_helper() 349 350 ~/anaconda3/lib/python3.7/asyncio/streams.py in _drain_helper(self) 200 async def _drain_helper(self): 201 if self._connection_lost: --> 202 raise ConnectionResetError('Connection lost') 203 if not self._paused: 204 return ConnectionResetError: Connection lost
请问有人能指出我哪里出错了吗?
解决思路
嘿,我来帮你捋清楚问题出在哪!你这里的核心问题是你启动的pwd命令是一次性执行的,输出结果后立刻就退出进程了,当你尝试往它的stdin写数据时,这个子进程已经不存在,对应的IO连接也已经关闭,自然就抛出了ConnectionResetError。
具体来说:
pwd是个短生命周期命令,完成目录输出后会马上终止,此时它的标准输入、输出流都会被系统关闭。- 你后续还想往这个已经终止的进程的
stdin写入python test.py,这相当于对着一个已经断开的连接发数据,肯定会报错。
另外还要提个小细节:你的代码最后调用asyncio.run(run_outer_py_file()),但定义的函数是external,这里名称不匹配,实际运行时会先报错找不到run_outer_py_file,得改成asyncio.run(external())才行。
下面给你两种可行的修改方案:
方案1:在同一个shell中执行多个命令
如果想先执行pwd再执行python test.py,可以把两个命令用&&串联,放在同一个create_subprocess_shell调用里:
import asyncio async def external(): # 串联两个命令,在同一个shell进程中执行 writing_process=await asyncio.create_subprocess_shell( "pwd && python test.py", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd="/home/user1/folder1" ) # 读取所有输出(包含pwd和test.py的输出) output = await writing_process.stdout.read() print(output) # 读取错误输出并处理 stderr_content = await writing_process.stderr.read() if stderr_content: print("错误信息:", stderr_content) # 等待进程执行完成 await writing_process.wait() asyncio.run(external())
方案2:创建两个独立的子进程
如果需要分开执行两个命令(先跑pwd,再跑python脚本),应该分别创建两个子进程实例:
import asyncio async def external(): # 第一个子进程:执行pwd pwd_process=await asyncio.create_subprocess_shell( "pwd", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd="/home/user1/folder1" ) print(await pwd_process.stdout.read()) # 等待pwd进程结束 await pwd_process.wait() # 第二个子进程:执行python test.py py_process=await asyncio.create_subprocess_shell( "python test.py", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd="/home/user1/folder1" ) # 如果test.py需要输入数据,再往stdin写入 # py_process.stdin.writelines([b"需要传入的输入内容"]) # await py_process.stdin.drain() print(await py_process.stdout.read()) await py_process.wait() asyncio.run(external())
内容的提问来源于stack exchange,提问作者A. Bykov




