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 sleep()
coroutine of the asyncio
package. The sleep()
function delays a specified number of the second:
await asyncio.sleep(seconds)
Code language: Python (python)
Because sleep()
is a coroutine, you need to use the await
keyword. For example, the following uses the sleep()
coroutine to simulate an API call:
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 create_task()
function of the asyncio
package. The create_task()
function returns a 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:
Leave a Reply