
Chào các 'dev-er' tương lai của Gen Z! Anh Creyt lại 'on air' đây, hôm nay chúng ta sẽ 'phá đảo' một khái niệm nghe hơi 'hàn lâm' nhưng thực ra 'chill phết' trong Python: asyncio.create_task.
1. asyncio.create_task: Nó là 'cái vẹo' gì và để làm gì?
"Thôi ngay cái kiểu 'chạy tuần tự' đi các em!" Đó là câu nói mà asyncio thì thầm vào tai chúng ta. Giống như các em đang lướt TikTok, xem YouTube, và chat với crush cùng lúc vậy. Các em không có 3 cái não để làm 3 việc đó thực sự song song đâu, mà là các em chuyển đổi qua lại giữa chúng cực kỳ nhanh và hiệu quả, đúng không? Đó chính là cái 'vibe' của asyncio.
asyncio trong Python giúp chúng ta viết code 'bất đồng bộ' (asynchronous) và 'đồng thời' (concurrently) – tức là, thay vì đợi một việc hoàn thành 100% rồi mới làm việc khác, ta có thể 'đá' việc đang đợi sang một bên và làm việc khác ngay lập tức. Cụ thể, khi một tác vụ nào đó đang 'await' (chờ đợi) một thứ gì đó (ví dụ: chờ dữ liệu từ mạng về, chờ đọc file, chờ database trả lời), thì thay vì đứng 'chôn chân' đợi, asyncio sẽ 'nhảy' sang làm việc khác.
Thế còn asyncio.create_task? Nó chính là 'thằng quản lý' hay 'tay đạo diễn' tài ba của chúng ta. Khi các em có một 'coroutine' (tức là một hàm async def – một kịch bản cần diễn), các em dùng create_task để nói với asyncio (cái 'sân khấu' event loop): "Ê, đạo diễn! Tôi có cái kịch bản này, anh cứ xếp lịch cho nó diễn đi, không cần phải đợi tôi diễn xong cái này mới được diễn cái kia đâu. Cứ đưa nó vào 'danh sách chờ' đi, khi nào có thời gian trống thì gọi nó lên sân khấu!"
Nói cách khác, create_task sẽ lên lịch cho một coroutine chạy trên 'vòng lặp sự kiện' (event loop) của asyncio mà không chặn việc thực thi của coroutine hiện tại. Nó trả về một đối tượng Task mà sau này các em có thể 'await' nó để lấy kết quả hoặc xử lý ngoại lệ.
2. Code Ví Dụ Minh Họa Rõ Ràng, Chuẩn Kiến Thức
Để các em dễ hình dung, hãy xem ví dụ này. Chúng ta có 3 'diễn viên' đang 'đợi' để 'diễn' các vai của mình. Nếu chạy tuần tự, sẽ phải đợi từng người một. Nhưng với asyncio.create_task, họ sẽ được 'lên lịch' và chạy 'xen kẽ' nhau, tối ưu thời gian chờ.
import asyncio
import time
async def say_hello(name, delay):
"""Một coroutine giả lập công việc tốn thời gian (I/O)."""
print(f"[{time.time():.2f}] 🎬 Anh {name} ơi, chuẩn bị diễn! Đợi {delay}s nha...")
await asyncio.sleep(delay) # Giả lập I/O: chờ mạng, database, file...
print(f"[{time.time():.2f}] ✅ Anh {name} đã diễn xong vai của mình.")
return f"Kết thúc vai của {name}"
async def main():
"""Hàm chính điều phối các tác vụ."""
print(f"[{time.time():.2f}] Bắt đầu buổi diễn chính...")
# Dùng asyncio.create_task để 'lên lịch' cho các diễn viên
task_an = asyncio.create_task(say_hello("An", 3)) # Lên lịch cho An, đợi 3s
task_binh = asyncio.create_task(say_hello("Bình", 1)) # Lên lịch cho Bình, đợi 1s
task_cuc = asyncio.create_task(say_hello("Cúc", 2)) # Lên lịch cho Cúc, đợi 2s
print(f"[{time.time():.2f}] 💡 Đã lên lịch cho các diễn viên. Sân khấu đang chờ...")
# Chờ tất cả các task hoàn thành. Đây là lúc 'đạo diễn' thu thập kết quả.
# asyncio.gather sẽ chờ tất cả các task được truyền vào hoàn thành
results = await asyncio.gather(task_an, task_binh, task_cuc)
print(f"[{time.time():.2f}] 👏 Buổi diễn kết thúc! Kết quả: {results}")
if __name__ == "__main__":
asyncio.run(main()) # Khởi động 'sân khấu' (event loop) và chạy buổi diễn
Giải thích:
Khi chạy đoạn code trên, các em sẽ thấy: An, Bình, Cúc không đợi nhau. Bình xong trước (1s), rồi đến Cúc (2s), và cuối cùng là An (3s). main function không bị 'đứng hình' mà ngay lập tức sau khi create_task đã in ra dòng "Đã lên lịch..." và chỉ await asyncio.gather khi cần chờ kết quả của tất cả.

3. Mẹo (Best Practices) để Ghi Nhớ và Dùng Thực Tế
- Đừng quên 'await' Task: Khi các em
create_task, nó chỉ là 'lên lịch' thôi. Để đảm bảo task đó chạy xong, lấy kết quả, hoặc bắt được lỗi của nó, các em phảiawaitnó (hoặcawaitmột nhóm task bằngasyncio.gather). Nếu không, nó sẽ chạy 'lang thang như con ghẻ không ai thèm ngó tới', có thể hoàn thành mà các em không biết, hoặc tệ hơn là lỗi mà không ai xử lý. create_taskvs.awaittrực tiếp:await some_async_func(): Hàmmain(hoặc coroutine hiện tại) sẽ đứng yên chờsome_async_funchoàn thành. Dùng khi các em cần kết quả ngay lập tức hoặc không muốn chạy song song với các tác vụ khác.task = asyncio.create_task(some_async_func()): Hàmmaintiếp tục chạy ngay lập tức.some_async_funcđược đẩy vào 'hàng đợi' đểasyncioxử lý khi có thời gian. Dùng khi các em muốn 'khởi động' nhiều tác vụ cùng lúc và 'thu thập' kết quả sau này (thường là vớiasyncio.gather).
- Sử dụng
asyncio.gathercho nhiều Tasks: Đây là cách 'xịn sò' nhất để chờ một loạt các task hoàn thành và thu thập kết quả của chúng một cách hiệu quả. Nó giống như việc 'thu hoạch' tất cả các thành quả sau khi 'gieo trồng' một loạt các nhiệm vụ vậy. - Xử lý lỗi (Error Handling): Một task có thể 'fail' (nổi loạn) và ném ra ngoại lệ. Hãy dùng
try...exceptkhiawaitmột task (hoặcgathercác task) để bắt và xử lý lỗi kịp thời.
4. Ứng Dụng Thực Tế
asyncio.create_task và asyncio nói chung là 'key' cho các ứng dụng cần xử lý hàng tá request cùng lúc mà không bị 'nghẽn cổ chai':
- Web Servers (FastAPI, Sanic, Aiohttp): Khi hàng ngàn người dùng truy cập website cùng lúc, mỗi request có thể được xử lý như một task riêng biệt.
create_taskgiúp server không bị 'đứng hình' khi một request đang chờ database hay một API bên thứ ba trả về. - API Clients: Khi các em cần gọi nhiều API khác nhau để lấy dữ liệu (ví dụ: lấy thông tin người dùng từ server A, lấy lịch sử mua hàng từ server B, lấy khuyến mãi từ server C). Thay vì đợi từng cái một,
create_taskgiúp gọi tất cả cùng lúc và chờ kết quả. Siêu nhanh! - Real-time Applications: Chat servers, game servers. Khi có hàng trăm người chơi gửi tin nhắn hay hành động, mỗi sự kiện có thể được biến thành một task để xử lý mà không làm chậm hệ thống.
- Data Scraping/Crawling: Khi các em muốn 'hốt' dữ liệu từ hàng ngàn trang web.
create_taskgiúp các em gửi hàng loạt yêu cầu HTTP đi cùng lúc thay vì đợi từng trang tải xong.
5. Thử Nghiệm và Nên Dùng Cho Case Nào
Anh Creyt đã 'chinh chiến' với asyncio đủ lâu để đúc kết ra rằng:
- Nên dùng khi: Các em có các tác vụ 'I/O-bound' – tức là các tác vụ mà phần lớn thời gian là 'chờ đợi' (chờ mạng, chờ đĩa, chờ database). Đây chính là 'sân chơi' của
asyncio. Nó giống như việc các em đặt đồ ăn online, thay vì ngồi nhìn màn hình đợi, các em có thể làm việc khác trong lúc chờ shipper tới.asynciosẽ 'nhắc' các em khi đồ ăn đến. - Tránh dùng khi: Các tác vụ 'CPU-bound' – tức là các tác vụ cần nhiều sức mạnh tính toán của CPU (ví dụ: xử lý hình ảnh phức tạp, tính toán khoa học nặng).
asynciochạy trên một luồng (thread) duy nhất, nên nếu một task 'ngốn' CPU quá lâu, nó sẽ 'block' toàn bộ event loop, khiến mọi tác vụ khác cũng bị đình trệ. Đối với các case này, hãy nghĩ đếnmultiprocessingđể tận dụng nhiều core CPU.
Lời khuyên từ anh Creyt: Hãy coi asyncio.create_task như một 'phó đạo diễn' đắc lực, giúp các em dàn xếp các cảnh quay một cách linh hoạt. Nắm vững nó, các em sẽ viết được những ứng dụng Python 'mượt mà' và 'thần tốc' hơn rất nhiều đó! Cứ thử nghiệm đi, 'code is life', mà 'life is async' mà, phải không?
Thuộc Series: Python
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!