Gọi 50 API, mỗi lần chờ 1 giây — chạy tuần tự mất 50 giây, nhưng thực ra CPU chỉ ngồi chờ. asyncio cho phép chờ đồng thời, rút xuống còn hơn 1 giây.
Hàm bất đồng bộ đầu tiên
import asyncio
async def chao(ten, giay):
await asyncio.sleep(giay) # nhường quyền trong lúc chờ
return f"Xin chào {ten}"
async def main():
ket_qua = await chao("An", 1)
print(ket_qua)
asyncio.run(main())
async def tạo một coroutine. Gọi nó không chạy ngay — phải await hoặc đưa vào vòng lặp sự kiện.
Điểm mấu chốt: gather
async def main():
ket_qua = await asyncio.gather(
chao("An", 1),
chao("Bình", 1),
chao("Cường", 1),
)
print(ket_qua) # mất ~1 giây, không phải 3
asyncio.run(main())
Gọi nhiều API thật với httpx
import asyncio, httpx
async def lay(client, url):
r = await client.get(url, timeout=10)
return url, r.status_code
async def main(urls):
async with httpx.AsyncClient() as client:
cong_viec = [lay(client, u) for u in urls]
for url, ma in await asyncio.gather(*cong_viec):
print(ma, url)
asyncio.run(main(["https://example.com", "https://python.org"]))
Giới hạn số việc chạy song song
sem = asyncio.Semaphore(10) # tối đa 10 request cùng lúc
async def lay_co_gioi_han(client, url):
async with sem:
return await lay(client, url)
Không giới hạn, bạn dễ bị máy chủ đích chặn hoặc làm nghẽn mạng.
Sai lầm thường gặp
- Dùng
time.sleep()trong hàm async — nó chặn cả vòng lặp; phải dùngasyncio.sleep(). - Dùng
requeststhay vìhttpx/aiohttp— thư viện đồng bộ sẽ chặn toàn bộ. - Quên
await— coroutine không chạy và Python cảnh báo “never awaited”.
Khi nào asyncio KHÔNG giúp
asyncio chỉ nhanh với tác vụ chờ I/O: mạng, đọc ghi file, truy vấn database. Với tính toán nặng CPU (xử lý ảnh, mã hóa), nó không giúp gì — lúc đó bạn cần multiprocessing.
