Summary: in this tutorial, you’ll learn how to use asyncio.create_task()
function to run multiple tasks concurrently.
Simulating a long-running operation
To simulate a long-running operation, you can use the
coroutine of the sleep()
asyncio
package. The
function delays a specified number of the second:sleep()
await asyncio.sleep(seconds)
Code language: Python (python)
Because
is a coroutine, you need to use the sleep()
await
keyword. For example, the following uses the
coroutine to simulate an API call:sleep()
import asyncio
async def call_api(message, result=1000, delay=3):
print(message)
await asyncio.sleep(delay)
return result
Code language: Python (python)
The call_api()
is a coroutine. It displays a message, pauses a specified number of seconds (default to three seconds), and returns a result.
The following program uses the call_api()
twice and measures the time it takes to complete:
import asyncio
import time
async def call_api(message, result=1000, delay=3):
print(message)
await asyncio.sleep(delay)
return result
async def main():
start = time.perf_counter()
price = await call_api('Get stock price of GOOG...', 300)
print(price)
price = await call_api('Get stock price of APPL...', 400)
print(price)
end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')
asyncio.run(main())
Code language: Python (python)
Output:
Get stock price of GOOG...
300
Get stock price of APPL...
400
It took 6.0 second(s) to complete.
Code language: Python (python)
How it works (focusing on the main()
coroutine):
First, start a timer to measure the time using the perf_counter()
function of the time
module:
start = time.perf_counter()
Code language: Python (python)
Second, call the call_api()
coroutine and display the result:
price = await call_api('Get stock price of GOOG...', 300)
print(price)
Code language: Python (python)
Third, call the call_api()
a second time:
price = await call_api('Get stock price of APPL...', 400)
print(price)
Code language: Python (python)
Finally, show the time the program takes to complete:
end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')
Code language: Python (python)
Because each call_api()
takes three seconds, and calling it twice takes six seconds.
In this example, we call a coroutine directly and don’t put it on the event loop to run. Instead, we get a coroutine object and use the await
keyword to execute it and get a result.
The following picture illustrates the execution flow of the program:
In other words, we use async
and await
to write asynchronous code but can’t run it concurrently. To run multiple operations concurrently, we’ll need to use something called tasks.
Introduction to Python tasks
A task is a wrapper of a coroutine that schedules the coroutine to run on the event loop as soon as possible.
The scheduling and execution occur in a non-blocking manner. In other words, you can create a task and execute other code instantly while the task is running.
Notice that the task is different from the await
keyword that blocks the entire coroutine until the operation completes with a result.
It’s important that you can create multiple tasks and schedule them to run instantly on the event loop at the same time.
To create a task, you pass a coroutine to the
function of the create_task()
asyncio
package. The
function returns a create_task()
Task
object.
The following program illustrates how to create two tasks that schedule and execute the call_api()
coroutine:
import asyncio
import time
async def call_api(message, result=1000, delay=3):
print(message)
await asyncio.sleep(delay)
return result
async def main():
start = time.perf_counter()
task_1 = asyncio.create_task(
call_api('Get stock price of GOOG...', 300)
)
task_2 = asyncio.create_task(
call_api('Get stock price of APPL...', 300)
)
price = await task_1
print(price)
price = await task_2
print(price)
end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')
asyncio.run(main())
Code language: Python (python)
Output:
Get stock price of GOOG...
Get stock price of APPL...
300
300
It took 3.0 second(s) to complete.
Code language: Python (python)
How it works.
First, start a timer:
start = time.perf_counter()
Code language: Python (python)
Next, create a task and schedule it to run on the event loop immediately:
task_1 = asyncio.create_task(
call_api('Get stock price of GOOG...', 300)
)
Code language: Python (python)
Then, create another task and schedule it to run on the event loop immediately:
task_2 = asyncio.create_task(
call_api('Get stock price of APPL...', 400)
)
Code language: Python (python)
After that, wait for the tasks to be completed:
price = await task_1
print(price)
price = await task_2
print(price)
Code language: Python (python)
It’s important to use the await
keyword to wait for the tasks at some point in the program.
If we did not use the await
keyword, Python would schedule the task to run but stopped it when the asyncio.run()
shutdown the event loop.
The following picture illustrates the execution flow of the program:
Finally, show the time it takes to complete the main()
function:
end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')
Code language: Python (python)
By using the create_task()
function, the program is much faster. The more tasks you run, the faster it is.
Running other tasks while waiting
When the call_api
is running, you can run other tasks. For example, the following program displays a message every second while waiting for the call_api
tasks:
import asyncio
import time
async def call_api(message, result=1000, delay=3):
print(message)
await asyncio.sleep(delay)
return result
async def show_message():
for _ in range(3):
await asyncio.sleep(1)
print('API call is in progress...')
async def main():
start = time.perf_counter()
message_task = asyncio.create_task(
show_message()
)
task_1 = asyncio.create_task(
call_api('Get stock price of GOOG...', 300)
)
task_2 = asyncio.create_task(
call_api('Get stock price of APPL...', 300)
)
price = await task_1
print(price)
price = await task_2
print(price)
await message_task
end = time.perf_counter()
print(f'It took {round(end-start,0)} second(s) to complete.')
asyncio.run(main())
Code language: Python (python)
Output:
Get stock price of GOOG...
Get stock price of APPL...
API call is in progress...
API call is in progress...
API call is in progress...
300
300
Code language: Python (python)
The following picture illustrates the execution flow:
Summary
- A task is a wrapper of a coroutine that schedules the coroutine to run on the event loop as soon as possible.
- Use the
create_task()
function of theasyncio
library to create a task. - Use the
await
keyword with the task at some point in the program so that the task can be completed before the event loop is closed by theasyncio.run()
function.