Description
Bug report
Bug description:
When checking asyncio subprocess .returncode
for example in a busy loop, it will never be set.
Minimal example:
import asyncio
async def main():
code = """
import time, sys
time.sleep(1)
print('proc exits')
"""
proc = await asyncio.create_subprocess_exec("python", "-c", code)
while proc.returncode is None:
pass
print("proc.returncode:", proc.returncode)
if __name__ == "__main__":
asyncio.run(main())
One would expect this code to wait 1 second, print proc exits
, followed by proc.returncode: 0
. However only proc exits
is printed, meaning that the parent process's asyncio never detected the process exiting.
This is problematic for what I would imagine is a relatively common and useful usecase (as was for me finding this bug): using a loop to get output from a child process.
import asyncio
import subprocess
async def main():
code = """
import time, sys
time.sleep(1)
print('proc exits')
"""
proc = await asyncio.create_subprocess_exec("python", "-c", code, stdout=subprocess.PIPE)
while proc.returncode is None:
print("proc said:", await proc.stdout.readline())
print("proc.returncode:", proc.returncode)
if __name__ == "__main__":
asyncio.run(main())
This will print:
proc said: b'proc exits\r\n'
proc said: b''
proc said: b''
proc said: b''
proc said: b''
proc said: b''
proc said: b''
proc said: b''
proc said: b''
...
I noticed that adding a small await asyncio.sleep(0.1)
before looping again will allow the returncode to be set, but this is not ideal. Especially considering the bug happens even when using await proc.stdout.readline()
in the loop, which hints to the user that this is done efficiently and asynchronously. Having to instead think about leaving enough CPU time to the event loop to detect the process exiting is not ideal and doesn't seem pythonic to me.
For the time being I worked around this issue for my usecase by checking proc.stdout.at_eof()
which seems to work fine.
Maybe when accessing .returncode
which is a property, it could use some CPU time to see if an exit event is pending? Not sure how it is implemented under the hood so that might not even make sense.
CPython versions tested on:
3.11
Operating systems tested on:
Windows
Metadata
Metadata
Assignees
Projects
Status