Reputation: 461
I have some code that will be running in a server. It can take a long time to run (minutes at least). I want to be able to poll the server for where in the code it currently is. I thought I could use asyncio
to do that, but it looks like it may not be what I need.
Here is some code that I wrote to test it (saved as test_async.py
):
import asyncio
import time
the_status = 'idle'
async def waiting():
global the_status
await asyncio.sleep(0.001)
the_status = 'running'
time.sleep(30)
the_status = 'finished'
def get_status():
global the_status
return the_status
async def main():
loop.create_task(waiting())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
I run this by opening the Python console and typing:
from test_async import *
What I expected to happen is that it would start running waiting()
, change the_status
to 'running', and then wait 30 seconds before turning the status to 'finished'. In the meantime, I should get the console prompt back and I would be able to get the current status by typing get_status()
.
What is actually happening is that the variable the_status
is never changing from its initial state of 'idle'.
Am I doing something wrong? Is asyncio not the answer to what I'm trying to do?
My Python version is 3.6.
Upvotes: 0
Views: 1968
Reputation: 155600
Am I doing something wrong?
The code has two issues:
main
just creates a task without awaiting it - you can think of create_task
as creating a "background" task. But in asyncio background tasks run only as long as the main loop does, so run_until_complete(main())
exits immediately because main()
returns immediately after creating the task. With the main loop stopping, the waiting
task doesn't have a chance to start executing.
waiting
calls time.sleep
, which is not allowed in asyncio. Asyncio is a cooperative multi-tasking system for JS-style callbacks and coroutines which suspend themselves when they await something that blocks. time.sleep
doesn't suspend, it just blocks the whole event loop thread. Executing legacy blocking code inside asyncio is correctly done with run_in_executor
.
Is asyncio not the answer to what I'm trying to do?
If you have some blocking code that you need executed "in the background", you should use threads.
import time, concurrent.futures
the_status = 'idle'
def waiting():
global the_status
time.sleep(0.001)
the_status = 'running'
time.sleep(30)
the_status = 'finished'
executor = concurrent.futures.ThreadPoolExecutor()
executor.submit(waiting)
Importing the code works as expected:
>>> import thr2
>>> thr2.the_status
'running'
Upvotes: 1