asyncio.Future: Nắm trùm tương lai bất đồng bộ Python!
Python

asyncio.Future: Nắm trùm tương lai bất đồng bộ Python!

Author

Admin System

@root

Ngày xuất bản

21 Mar, 2026

Lượt xem

8 Lượt

"asyncio_future"

asyncio.Future: Chìa khóa vàng mở cánh cửa bất đồng bộ Python!

Chào các đệ tử Gen Z năng động! Hôm nay, anh Creyt sẽ cùng các em "quay xe" vào một khái niệm nghe hơi "hack não" nhưng lại là xương sống của lập trình bất đồng bộ trong Python: asyncio.Future. Nghe Future là thấy tương lai rồi đúng không? Chính nó đấy!

1. asyncio.Future là gì và để làm gì? (Genz Edition)

Tưởng tượng thế này, các em đang ngồi ở quán trà sữa "hot hit", order một ly Trà Sữa Trân Châu Đường Đen Full Topping. Các em trả tiền xong, chị nhân viên đưa cho các em một cái "bill" có số thứ tự. Cái bill đó chính là asyncio.Future của chúng ta!

Tại thời điểm đó, các em chưa có ly trà sữa trong tay (kết quả), nhưng các em có một cái "lời hứa" rằng ly trà sữa đó sẽ được làm xong và giao cho các em sau này. asyncio.Future trong Python cũng vậy, nó là một đối tượng "đặt chỗ" cho một kết quả mà một hàm bất đồng bộ sẽ trả về trong tương lai. Nó đại diện cho trạng thái của một hoạt động bất đồng bộ chưa hoàn thành.

Vậy cái "bill" này để làm gì?

  • Theo dõi tiến độ: Các em nhìn vào số thứ tự trên bill để biết khi nào đến lượt mình. Tương tự, code của các em có thể "hỏi thăm" Future xem nó đã hoàn thành chưa (done()), có lỗi không (exception()), hay đã có kết quả chưa (result()).
  • Phối hợp công việc: Khi các em order nhiều món cùng lúc (ví dụ, trà sữa, bánh mì nướng, kem), mỗi món có một bill riêng. Các em có thể đợi từng món một hoặc đợi tất cả cùng lúc. Future giúp các đoạn code khác nhau "chờ" kết quả của một tác vụ bất đồng bộ mà không cần phải biết chi tiết tác vụ đó đang chạy như thế nào.
  • Cầu nối giữa các thế giới: Đôi khi, các em có những thư viện không phải asyncio nhưng lại muốn thông báo kết quả cho một chương trình asyncio. Future chính là "người đưa tin" hoàn hảo. Nó giúp các em "nhúng" các hoạt động không đồng bộ vào môi trường asyncio một cách mượt mà.

2. Code Ví Dụ Minh Hoạ: Future và Task

Để các em dễ hình dung, anh Creyt sẽ "show hàng" code ví dụ. Chúng ta sẽ thấy cách dùng asyncio.Future ở cấp độ thấp và so sánh nó với asyncio.Task - "anh em" cùng nhà nhưng ở cấp độ cao hơn và thường được dùng hơn.

import asyncio
import time

async def worker_with_future(future_obj):
    """
    Một 'nhân viên' làm việc bất đồng bộ, sau đó 'đặt kết quả' vào Future.
    Tưởng tượng đây là người pha chế trà sữa.
    """
    print("\t[Worker] Nhân viên bắt đầu làm việc (async worker).")
    await asyncio.sleep(2)  # Giả lập công việc tốn 2 giây
    print("\t[Worker] Nhân viên hoàn thành công việc và đặt kết quả vào Future.")
    future_obj.set_result("Ly trà sữa Trân Châu Đường Đen Full Topping!")

async def main_future_example():
    print("\n--- Ví dụ với asyncio.Future (cấp độ thấp) ---")
    loop = asyncio.get_running_loop()
    my_future = loop.create_future() # Tạo một Future rỗng, như một cái bill trống

    # Chạy worker_with_future trong một Task, truyền Future vào
    # Worker này sẽ 'set_result' cho my_future khi hoàn thành
    asyncio.create_task(worker_with_future(my_future))

    print("[Main] Main đang làm việc khác trong khi chờ Future...")
    await asyncio.sleep(1) # Main làm việc khác trong 1 giây
    print("[Main] Main đã làm việc khác xong, giờ đợi Future có kết quả...")

    # Chờ đợi Future hoàn thành và lấy kết quả
    # Dòng này sẽ 'treo' Main cho đến khi my_future có kết quả
    result = await my_future
    print(f"[Main] Main đã nhận được kết quả từ Future: '{result}'")

async def simple_task_example():
    """
    Ví dụ đơn giản với asyncio.Task (cấp độ cao hơn) để so sánh.
    Task là một Future đặc biệt, nó tự động bọc một coroutine.
    """
    print("\n--- Ví dụ với asyncio.Task (cấp độ cao) ---")
    async def simple_job():
        print("\t[Task] Simple Job bắt đầu.")
        await asyncio.sleep(1.5) # Giả lập công việc 1.5 giây
        print("\t[Task] Simple Job hoàn thành.")
        return "Kết quả từ Simple Job (đã được bọc trong Task)!"

    print("[Main] Main tạo Simple Job Task.")
    # create_task tự động tạo một Task (là một loại Future) và lên lịch chạy coroutine
    task = asyncio.create_task(simple_job())

    print("[Main] Main làm việc khác trong khi chờ Task...")
    await asyncio.sleep(0.5)
    print("[Main] Main đã làm việc khác xong, giờ đợi Task...")

    result = await task # Chờ Task hoàn thành và lấy kết quả
    print(f"[Main] Main đã nhận được kết quả từ Task: '{result}'")

async def main():
    await main_future_example()
    await simple_task_example()

# Để chạy chương trình này, các em dùng:
# asyncio.run(main())

# Chú ý: Khi chạy, các em sẽ thấy các thông báo [Main], [Worker], [Task] xen kẽ nhau,
# chứng tỏ các tác vụ đang chạy bất đồng bộ!

Giải thích nhanh: Trong ví dụ main_future_example, my_future được tạo ra rỗng. Hàm worker_with_future được chạy trong một Task riêng, và nó có nhiệm vụ set_result cho my_future sau khi hoàn thành. main function thì cứ làm việc của nó, sau đó await my_future để chờ kết quả. Các em sẽ thấy "Main làm việc khác" trong khi "Nhân viên đang làm việc", đó chính là sức mạnh của bất đồng bộ!

Illustration

3. Mẹo (Best Practices) từ anh Creyt

Để không bị "toang" khi dùng asyncio.Future, các em cần nhớ mấy mẹo "xịn xò" này:

  • Ưu tiên asyncio.Task (90% trường hợp): Các em ơi, asyncio.Future giống như "nguyên liệu thô" vậy. Hầu hết các trường hợp, các em sẽ dùng asyncio.Task nhiều hơn. Task là một Future đặc biệt, nó tự động "bọc" và chạy một coroutine (hàm async def) trong event loop. Nó tiện lợi hơn rất nhiều! Coi Task như ly trà sữa đã pha sẵn, còn Future là từng nguyên liệu riêng lẻ.
  • Dùng loop.create_future(): Thay vì asyncio.Future(), hãy dùng asyncio.get_event_loop().create_future() hoặc asyncio.create_task() (cho Task). Nó đảm bảo Future được tạo ra gắn liền với event loop hiện tại, tránh các lỗi khó chịu.
  • Xử lý CancelledError: Đôi khi, một Future có thể bị hủy giữa chừng (ví dụ, người dùng đóng ứng dụng). Hãy luôn chuẩn bị tinh thần xử lý asyncio.CancelledError khi await một Future để chương trình không bị crash.
  • Đừng bao giờ block event loop! Mục tiêu của asyncio là không bao giờ để một tác vụ chặn toàn bộ hệ thống. Khi các em await một Future, hãy đảm bảo nó sẽ hoàn thành trong thời gian hợp lý, hoặc ít nhất là không chặn các tác vụ khác. Nếu có tác vụ tốn CPU, hãy dùng loop.run_in_executor().

4. Ứng dụng thực tế: "Flex" sức mạnh của Future

asyncio.Future (và asyncio.Task nói riêng) là trái tim của rất nhiều ứng dụng "khủng" hiện nay:

  • Các hệ thống web server hiệu năng cao: Như FastAPI hay Starlette (dựa trên ASGI) sử dụng asyncio và các đối tượng Future/Task để xử lý hàng ngàn yêu cầu cùng lúc mà không cần tạo nhiều luồng. Mỗi request có thể được coi là một "Future" đang chờ kết quả từ database, API khác.
  • Các ứng dụng xử lý dữ liệu thời gian thực: Nơi bạn cần thu thập dữ liệu từ nhiều nguồn (sensor, message queue) và xử lý chúng một cách song song mà không bị tắc nghẽn. Ví dụ, hệ thống phân tích dữ liệu IoT, các dashboard real-time.
  • Game servers hoặc các ứng dụng chat: Nơi cần duy trì kết nối với hàng trăm, hàng ngàn client và phản hồi nhanh chóng mà không làm chậm trải nghiệm người dùng. Mỗi tin nhắn, mỗi hành động trong game đều có thể được quản lý như một Future.

5. Thử nghiệm và hướng dẫn dùng cho từng case

Vậy khi nào thì anh em "đệ tử" nên dùng asyncio.Future trần trụi, còn khi nào dùng asyncio.Task?

  • Dùng asyncio.Task (90% trường hợp - "default setting"):

    • Khi nào: Khi các em muốn chạy một coroutine (hàm async def) ở chế độ bất đồng bộ và muốn có một đối tượng để theo dõi kết quả của nó. Đây là cách phổ biến nhất và tiện lợi nhất. Nó giống như việc các em gọi asyncio.create_task(pha_tra_sua()) và sau đó await cái task đó.
    • Ví dụ: task = asyncio.create_task(my_async_function()).
  • Dùng asyncio.Future (10% trường hợp - cho dân "pro" hơn, "custom build"):

    • Khi nào: Khi các em cần tích hợp code không phải asyncio vào event loop. Ví dụ, các em có một thư viện sử dụng callback hoặc một luồng riêng để thực hiện một công việc, và khi công việc đó hoàn thành, các em muốn "báo" cho event loop biết. Lúc này, các em sẽ tạo một Future, truyền nó cho thư viện/luồng đó, và khi công việc hoàn thành, thư viện/luồng đó sẽ gọi future.set_result() hoặc future.set_exception() để "hoàn tất" lời hứa.
    • Ví dụ: Các em đang dùng một thư viện C++ qua ctypes để thực hiện một tác vụ nặng. Thư viện đó có một hàm callback khi hoàn thành. Các em có thể tạo một asyncio.Future, truyền nó vào callback, và khi callback được gọi, nó sẽ set_result cho Future đó, từ đó thông báo cho event loop biết tác vụ đã xong.

Đó, asyncio.Future không chỉ là một khái niệm khô khan mà nó là một công cụ cực kỳ mạnh mẽ, giúp các em "cân" được hàng tá công việc cùng lúc mà không làm nghẽn hệ thống. Hiểu rõ nó là các em đã nắm trong tay chìa khóa để viết ra những ứng dụng Python "mượt mà" và "phê pha" rồi đấy! Cứ thực hành đi, có gì "bí" thì hỏi anh Creyt nhé!

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é!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!