Module asyncio
Coroutine object, viết tắt là coro, thường được gọi là coro object.
Tổng quan
- Module asyncio: Được giới thiệu từ phiên bản Python 3.4, hỗ trợ các thao tác I/O không đồng bộ.
- Mô hình lập trình: Sử dụng một vòng lặp sự kiện, lấy EventLoop từ module asyncio, và thực hiện các coroutine trong EventLoop để đạt được I/O không đồng bộ.
- Lưu ý: Hiện nay, không chỉ asyncio, mà cả tornado và gevent cũng cung cấp chức năng tương tự.
Giải thích các từ khóa
| Từ khóa | Giải thích |
|---|---|
| event_loop | Vòng lặp sự kiện, chương trình khởi tạo một vòng lặp vô hạn, đăng ký các hàm vào vòng lặp, khi sự kiện xảy ra, gọi các coroutine tương ứng. |
| coroutine | Coroutine object, định nghĩa bằng từ khóa async, khi gọi sẽ trả về một coroutine object. Coroutine object cần được đăng ký vào vòng lặp sự kiện để được gọi. |
| task | Nhiệm vụ, một coroutine object là một hàm có thể tạm dừng, task là bọc ngoài coroutine, chứa các trạng thái của nhiệm vụ. |
| async/await | Từ khóa trong Python 3.5 để định nghĩa coroutine, async định nghĩa một coroutine, await dùng để tạm dừng các gọi API không đồng bộ. |
Đồng bộ là gì?
Một ví dụ về nhiệm vụ đồng bộ:
import time
def chay(c):
print('Nhiệm vụ bắt đầu=====', c)
time.sleep(4)
print('Nhiệm vụ kết thúc=====', c)
if __name__ == '__main__':
t1 = time.time()
for i in range(1, 4):
chay(i)
t2 = time.time()
print("Tổng thời gian: %.2f" % (t2 - t1))
Kết quả chạy:
Nhiệm vụ bắt đầu===== 1 Nhiệm vụ kết thúc===== 1 Nhiệm vụ bắt đầu===== 2 Nhiệm vụ kết thúc===== 2 Nhiệm vụ bắt đầu===== 3 Nhiệm vụ kết thúc===== 3 Tổng thời gian: 12.00
Bất đồng bộ (Coroutine) là gì?
Chuyển đổi nhiệm vụ đồng bộ thành bất đồng bộ (Coroutine):
import asyncio
import time
async def chay(i):
print('Nhiệm vụ bắt đầu=====', i)
await asyncio.sleep(4)
print('Nhiệm vụ kết thúc=====', i)
if __name__ == '__main__':
t1 = time.time()
danh_sach_nhiem_vu = []
for i in range(1, 4):
c = chay(i) # Coroutine object
task = asyncio.ensure_future(c)
danh_sach_nhiem_vu.append(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(danh_sach_nhiem_vu))
t2 = time.time()
print("Tổng thời gian: %.2f" % (t2 - t1))
Kết quả chạy:
Nhiệm vụ bắt đầu===== 1 Nhiệm vụ bắt đầu===== 2 Nhiệm vụ bắt đầu===== 3 Nhiệm vụ kết thúc===== 1 Nhiệm vụ kết thúc===== 2 Nhiệm vụ kết thúc===== 3 Tổng thời gian: 4.02
Sử dụng `asyncio.gather(*tasks)`
`await asyncio.gather(*tasks)` là cách hiện đại và được khuyến nghị, nó đơn giản hóa quy trình thực thi coroutine. `asyncio.gather` nhận một nhóm coroutine và trả về một future, future này sẽ hoàn thành khi tất cả coroutine đều hoàn thành. Sử dụng `await` có thể trực tiếp chờ future hoàn thành, không cần phải lấy và đóng vòng lặp sự kiện.
import asyncio
async def chay(c):
print('Bắt đầu nhiệm vụ=====', c)
await asyncio.sleep(4)
print('Kết thúc nhiệm vụ=====', c)
async def main():
tasks = []
for i in range(1, 4):
coro = chay(i)
task = asyncio.create_task(coro)
tasks.append(task)
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
So sánh `asyncio.run(main())` và `loop.run_until_complete(main())`
`asyncio.run(main())` là hàm tiện lợi được giới thiệu từ Python 3.7, tự động quản lý vòng đời của vòng lặp sự kiện, tạo, chạy và đóng vòng lặp. Nó giúp mã nguồn ngắn gọn hơn.
`loop.run_until_complete(main())` là cách tiếp cận thấp hơn, yêu cầu lấy vòng lặp sự kiện và gọi `run_until_complete()` để chạy hàm async. Cách này linh hoạt hơn nhưng cần quản lý vòng lặp sự kiện.
So sánh `asyncio.ensure_future(coro)` và `asyncio.create_task(coro)`
`asyncio.ensure_future()` là hàm thông dụng, có thể nhận một coroutine hoặc đối tượng có thể đợi, và trả về một task. Nếu đối tượng đã là task, nó sẽ trả về đối tượng đó; nếu là coroutine, nó sẽ tạo một task mới.
`asyncio.create_task()` là hàm mới, chỉ nhận coroutine và trả về task. Nó được giới thiệu từ Python 3.7, chuyên dùng để tạo task.