Reputation: 226
I'm excuting a shell command by os.system()
. I planned to run it for 1 second, then terminate it if time exceeded. Here's what I tried instead as a test.
import os, time, asyncio
async def cmd():
os.system("my.py > my.txt") # this processes longer than 1 second
@asyncio.coroutine
def run():
try:
yield from asyncio.wait_for(cmd(), 1) # this should excute for more than 1 sec, and hence raise TimeoutError
print("A")
except asyncio.TimeoutError:
os.system("killall python")
print("B")
asyncio.run(run())
But the result was always "A" and the txt was written by my.py.
I also tried:
import os, time, asyncio
async def cmd():
os.system("my.py > my.txt") # longer than 1 sec
async def run():
try:
await asyncio.wait_for(cmd(), 1) # should raise TimeoutError
print("A")
except asyncio.TimeoutError:
os.system("killall python")
print("B")
asyncio.run(run())
results in the same output.
What's wrong with the code? I'm pretty new to asyncio and never used it before. Thanks in advance. It's most likely not the problem that wait_for
does not stop the cast automatically, since I have a killall python
in the second part and in fact, the wait_for function never raises the timeout error, that's the problem.
Upvotes: 2
Views: 2043
Reputation: 198304
os.system
is a blocking operation, so it doesn't play well with asyncio
. Whenever you use asyncio
, all "longer" operations need to be asynchronous, or you lose all benefits of going with asyncio
in the first place.
import asyncio
async def cmd():
try:
proc = await asyncio.create_subprocess_shell(
"sleep 2 && date > my.txt",
shell=True,
stdout=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.DEVNULL)
await proc.communicate()
except asyncio.CancelledError:
proc.terminate()
print("X")
async def run():
try:
await asyncio.wait_for(cmd(), 1)
print("A")
except asyncio.TimeoutError:
print("B")
asyncio.run(run())
As @dim mentions in comments, asyncio.create_subprocess_exec
will launch an external command asynchronously. wait_for
will actually raise two exceptions: TimeoutError
in the awaiting code, and CancelledError
in the awaited code. We can use the latter to realise the operation was cancelled, and to terminate
or kill
our subprocess (as this is not done automatically).
Upvotes: 2