Python 对asyncio子进程调用.terminate()会引发ProcessLookupError
我有一些使用子进程的非异步代码Python 对asyncio子进程调用.terminate()会引发ProcessLookupError,python,subprocess,python-asyncio,Python,Subprocess,Python Asyncio,我有一些使用子进程的非异步代码 import subprocess import signal p = subprocess.Popen(['/bin/true'], stdout=subprocess.PIPE) # ... do something else here ... # The process may or may not have finished yet. # For the sake of this test, let us ensure a finish here #
import subprocess
import signal
p = subprocess.Popen(['/bin/true'], stdout=subprocess.PIPE)
# ... do something else here ...
# The process may or may not have finished yet.
# For the sake of this test, let us ensure a finish here
# by waiting for EOF on a pipe.
p.stdout.read()
p.terminate()
我尝试将其迁移到asyncio。但是,.terminate()
调用会引发ProcessLookupError
import asyncio
import asyncio.subprocess
import signal
async def main():
p = await asyncio.create_subprocess_exec('/bin/true',
stdout=asyncio.subprocess.PIPE)
# ... do something else here ...
# for the sake of this test, ensure a finish here
await p.stdout.read()
p.terminate()
asyncio.run(main())
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/usr/lib64/python3.8/asyncio/runners.py”,第43行,运行中
返回循环。运行直到完成(主)
文件“/usr/lib64/python3.8/asyncio/base_events.py”,第616行,运行直到完成
返回future.result()
文件“”,第6行,主
文件“/usr/lib64/python3.8/asyncio/subprocess.py”,第141行,终止
self.\u传输终止()
文件“/usr/lib64/python3.8/asyncio/base_subprocess.py”,第149行,终止
自我检查程序()
文件“/usr/lib64/python3.8/asyncio/base_subprocess.py”,第142行,在检查过程中
提升ProcessLookupError()
ProcessLookupError
这段代码中的错误是什么?我做错了什么
我在以下版本上进行了测试:
- python39-3.9.0-1.fc32.x86_64
- python3-3.8.5-5.fc32.x86_64
.terminate()
之前,请使用p.returncode
检查进程是否已返回。这同样适用于调用.kill()
或.send\u signal()
此代码是安全的。[*]无法在检查和.terminate()
调用之间“收获”进程。只有在异步函数正在等待时才能获取进程(await
语句)
我撒谎了,这不安全。现在来看,Unix进程可能会立即收获成果。这看起来像是一个非常恼人的比赛条件
讨论
在非异步子流程
模块中,调用.wait()
是获取流程并设置.returncode
的操作。如果尚未调用.wait()
,则不会设置.returncode
。如果UNIX进程退出但尚未收获,它将继续作为“僵尸”存在
在asyncio
中,事件循环重新获取进程并设置.returncode
。这可能发生在函数中的任何wait
语句中。目前的文件没有提到这一点。获取Unix进程意味着它不再存在。没有什么可以发送信号的
理论上,asyncio
可以更改为允许问题中的代码。但是,存在向后兼容性问题。到目前为止,我怀疑有些程序依赖于.returncode
设置而不在之前进行设置。wait()
,尽管它没有被记录在案。要设置.returncode
,必须重新执行Unix进程
最向后兼容的更改可能是asyncio
自己执行检查。这对使用p.pid
调用os.kill()
的代码没有帮助。这样的代码不太可能得到支持。(首先,除非您删除或降级了FastChildWatcher,否则无法使用可移植Unix系统调用支持它)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.8/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/usr/lib64/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "<stdin>", line 6, in main
File "/usr/lib64/python3.8/asyncio/subprocess.py", line 141, in terminate
self._transport.terminate()
File "/usr/lib64/python3.8/asyncio/base_subprocess.py", line 149, in terminate
self._check_proc()
File "/usr/lib64/python3.8/asyncio/base_subprocess.py", line 142, in _check_proc
raise ProcessLookupError()
ProcessLookupError
if p.returncode is None:
p.terminate()