Coroutine
Before learning coroutine, let see the history of Process and Thread. Coroutine is better than them in most cases.
Coroutine uses event loop, controls the timing of each tasks.
To learn more about event loop, check nginx.
Coroutine needs async I/O
.
import time
import asyncio
async def worker_1():
print('worker_1 start')
await asyncio.sleep(1)
print('worker_1 done')
async def worker_2():
print('worker_2 start')
await asyncio.sleep(2)
print('worker_2 done')
async def main():
print('before await')
await worker_1()
print('awaited worker_1')
await worker_2()
print('awaited worker_2')
%time asyncio.run(main())
########## output ##########
before await
worker_1 start
worker_1 done
awaited worker_1
worker_2 start
worker_2 done
awaited worker_2
Wall time: 3 s
In this example, all the function are async
. However, we use async / await
to make them run sync
.
To run them in coroutine, we need to create task
using asyncio.create_task
.
import asyncio
async def worker_1():
print('worker_1 start')
await asyncio.sleep(1)
print('worker_1 done')
async def worker_2():
print('worker_2 start')
await asyncio.sleep(2)
print('worker_2 done')
async def main():
task1 = asyncio.create_task(worker_1())
task2 = asyncio.create_task(worker_2())
print('before await')
await task1
print('awaited worker_1')
await task2
print('awaited worker_2')
%time asyncio.run(main())
########## output ##########
before await
worker_1 start
worker_2 start
worker_1 done
awaited worker_1
worker_2 done
awaited worker_2
Wall time: 2.01 s
In this exemple, we did following thing:
- run
asyncio.run(main())
: start event loop - create 2 tasks
- run
await task1
: leave themain
, enterworker_1
- run
await asyncio.sleep(1)
inworker_1
: leaveworker_1
, enterworker_2
- run
await asyncio.sleep(2)
inworker_2
: leaveworker_2
, enterworker_1
6.work_1
finished: leaveworker_1
, entermain
- run
print('awaited worker_1')
: leavemain
, enterworker_2
worker_2
finished: leaveworker_2
, entermain
As we can see, main
, worker_1
, worker_2
works together. One of them sleeps, we run one of the rest.
There is another way to run tasks:
await asyncio.gather(task_1, task_2)
It's simpler.