8.7. Event¶
asyncio.Event là nguyên thủy báo hiệu đơn giản nhất mà module cung cấp. Một coroutine thiết lập một event khi có điều gì đó xảy ra; bất kỳ số coroutine khác nào chờ event được thiết lập trước khi tiếp tục. Không có payload -- một event là một boolean bật lên và ở lại bật cho đến khi có gì đó xóa nó.
8.7.1. Dạng cơ bản¶
import asyncio
async def waiter(evt):
print("waiting")
await evt.wait()
print("got signal")
async def main():
evt = asyncio.Event()
asyncio.create_task(waiter(evt))
await asyncio.sleep(1)
evt.set()
await asyncio.sleep(0)
asyncio.run(main())
Task waiter chạy, gặp await evt.wait(), và bị tạm dừng -- event bắt đầu ở trạng thái đã xóa, vì vậy lời gọi wait nhường lại cho loop. Một giây sau, main gọi evt.set() và waiter được lên lịch để tiếp tục. await asyncio.sleep(0) ở cuối chỉ là một yield để loop có cơ hội chạy waiter trước khi main trả về.
8.7.2. Bốn phương thức¶
set()-- bật event thành đã thiết lập, và lên lịch cho mọi coroutine hiện đang bị chặn trênwait()để tiếp tục. Event ở lại đã thiết lập cho đến khi bị xóa.clear()-- lật event trở lại trạng thái đã xóa. Các coroutineawait wait()sau đó sẽ bị chặn lại.wait()-- một coroutine. Nếu event đã được thiết lập, trả về ngay lập tức. Nếu không, chặn cho đến khi có gì đó thiết lập nó.is_set()-- trả về trạng thái hiện tại mà không chặn. Hữu ích khi một coroutine muốn kiểm tra event mà không chờ nó.
8.7.3. Nhiều waiter¶
Nhiều coroutine có thể await cùng một event. Khi có gì đó gọi set(), tất cả chúng đều được lên lịch để tiếp tục. Event mặc định là một-đến-nhiều; không cần nhiều event để fan out đến nhiều waiter.
8.7.4. Tái sử dụng một event¶
Một mẫu phổ biến là sử dụng một event nhiều lần -- một coroutine chạy một lần mỗi tín hiệu -- bằng cách xóa nó sau mỗi lượt:
async def worker(go):
while True:
await go.wait()
do_one_unit_of_work()
go.clear()
Producer thiết lập event mỗi khi có công việc; worker xóa nó sau khi đã nhận tín hiệu. Nếu producer có thể thiết lập event lại trước khi worker thức dậy, worker có thể muốn xử lý trường hợp đó (while go.is_set(): ...) trước khi xóa.
8.7.5. Ngữ cảnh an toàn¶
Event không an toàn để gọi set() từ bên trong một trình xử lý ngắt. Cơ chế nó dùng để lên lịch cho các waiter giả định rằng nó đang chạy bên trong ngữ cảnh riêng của event loop, mà các ngắt không phải vậy. Để đánh thức một asyncio task từ trình xử lý ngắt, ThreadSafeFlag (được đề cập sắp tới) là nguyên thủy đúng.