asyncio
in Pythonasyncio
is a Python library that helps you run multiple tasks at the same time without waiting for one to finish before starting another. This is very useful when your program needs to wait for things like file reading, network calls, or database access.
If you are new to asyncio
, don't worry! This guide will explain it step by step in simple terms.
In normal programming (called synchronous programming), tasks happen one after another. If Task A takes 5 seconds, Task B will only start after Task A finishes.
In asynchronous programming, you can start Task A, do other work while waiting for it to finish, and then come back to Task A when it's ready. This saves time and makes your program faster when dealing with tasks like I/O (input/output).
Example:
Synchronous: Finish Task A -> Wait -> Start Task B.
Asynchronous: Start Task A -> Do other work -> Return to Task A -> Start Task B.
asyncio
The event loop is the "brain" of asyncio
. It decides which task runs and when. It keeps checking for tasks to run and manages them efficiently.
Coroutines are special functions in Python that support asynchronous programming. They are created using async def
.
import asyncio
async def my_task():
print("Hello, Asyncio!")
await
KeywordThe await
keyword is used to pause a coroutine until the task is finished. It tells the program to "wait here" and come back when ready.
async def do_something():
await asyncio.sleep(2) # Wait for 2 seconds
print("Task done!")
Tasks are used to run coroutines. asyncio.create_task()
schedules a coroutine to run in the background.
asyncio
ProgramHere is a basic example to get started:
import asyncio
async def say_hello():
print("Hello!")
await asyncio.sleep(1) # Pause for 1 second
print("Hello again!")
async def main():
print("Program started")
await say_hello()
print("Program finished")
asyncio.run(main())
Output:
Program started
Hello!
Hello again!
Program finished
Explanation:
async def
defines the coroutine.
await
tells the program to pause and wait.
asyncio.run(main())
starts the program.
asyncio.gather()
Here is an example of running two coroutines at the same time using asyncio.gather()
:
import asyncio
async def say_hello1():
print("Hello1!")
await asyncio.sleep(1) # Pause for 1 second
print("Hello1 again!")
async def say_hello2():
print("Hello2!")
await asyncio.sleep(1) # Pause for 1 second
print("Hello2 again!")
async def main():
print("Program started")
await asyncio.gather(say_hello1(), say_hello2())
print("Program finished")
asyncio.run(main())
Output:
Program started
Hello1!
Hello2!
Hello1 again!
Hello2 again!
Program finished
Explanation:
asyncio.gather()
runs say_hello1()
and say_hello2()
at the same time.
Both coroutines start, and the program pauses for 1 second for each.
After both finish, the program continues.
asyncio.run
in Real-World ExamplesThe asyncio.run()
function is used to start the event loop and run your main coroutine. Below is a practical example where we fetch historical and real-time data using the Alpaca API for cryptocurrencies like BTC/USD and ETH/USD.
import asyncio
from alpaca.data.historical.crypto import CryptoHistoricalDataClient
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from alpaca.data.timeframe import TimeFrame, TimeFrameUnit
from alpaca.data.requests import CryptoBarsRequest
from alpaca.data.live.crypto import CryptoDataStream
from credentials import api_key, secret_key
# Initialize Historical Data Client
crypto_historical_data_client = CryptoHistoricalDataClient()
# Historical Data Retrieval Function
async def get_history():
while True:
symbol = "BTC/USD"
now = datetime.now(ZoneInfo("America/New_York"))
req = CryptoBarsRequest(
symbol_or_symbols=[symbol],
timeframe=TimeFrame(amount=1, unit=TimeFrameUnit.Minute),
start=now - timedelta(days=1),
)
history_df2 = crypto_historical_data_client.get_crypto_bars(req).df
print("Historical Data:")
print(history_df2)
await asyncio.sleep(10) # Wait for 10 seconds before fetching again
# Initialize Data Stream Client
crypto_data_stream_client = CryptoDataStream(api_key, secret_key)
# Live Data Stream Handler
async def crypto_data_stream_handler(data):
print(data)
# Function to Start the Live Stream
async def start_crypto_stream():
symbol = ['BTC/USD', 'ETH/USD']
crypto_data_stream_client.subscribe_quotes(crypto_data_stream_handler, *symbol)
print("Starting Live Data Stream...")
await crypto_data_stream_client._run_forever() # Await the internal run method
# Main Function to Run Both Tasks Concurrently
async def main():
# Run both tasks concurrently
await asyncio.gather(
get_history(), # Historical data retrieval every 10 seconds
start_crypto_stream() # Live data stream
)
asyncio.run(main())
Historical Data:
The get_history
function fetches historical data for the last day for BTC/USD every 10 seconds.
Live Stream:
The start_crypto_stream
function subscribes to real-time data for BTC/USD and ETH/USD using the Alpaca live stream API.
Concurrent Execution:
Using asyncio.gather
, both tasks (historical and real-time data fetching) run at the same time.
asyncio
Web Scraping: Downloading many web pages at the same time.
APIs: Sending and receiving data without blocking the program.
Servers: Handling multiple users at once.
Databases: Querying databases efficiently.
Delays: Simulating waiting times.
Always use asyncio.run()
to start your program.
Use await
only for I/O tasks like network requests or waiting.
Avoid blocking calls like time.sleep()
; use asyncio.sleep()
instead.
Use asyncio.gather()
to run tasks concurrently.
asyncio
helps you write programs that do multiple tasks at the same time, especially when waiting for input/output operations. It is easy to start with async def
, await
, and asyncio.run()
.
With a bit of practice, you can use asyncio
to build faster and more efficient programs. Try the examples here and experiment with your own tasks.