8.9. ThreadSafeFlag¶
asyncio.ThreadSafeFlag là nguyên thủy báo hiệu asyncio cung cấp cho trường hợp Event không hỗ trợ: một trình xử lý ngắt cần đánh thức một asyncio task. Ngắt kích hoạt bên ngoài lịch trình bình thường của event loop, vì vậy các bookkeeping mà asyncio.Event.set() thực hiện không thể được thực hiện an toàn từ bên trong nó.
8.9.1. Tại sao lại có nguyên thủy riêng¶
asyncio.Event.set() chạy bookkeeping đánh thức các coroutine đang chờ với giả định rằng nó đang được gọi từ bên trong một task mà loop hiện đang chạy. Một trình xử lý ngắt không đáp ứng giả định đó -- nó có thể kích hoạt giữa bất kỳ hai lệnh nào và làm hỏng bất cứ thứ gì mà loop đang thực hiện dở.
asyncio.ThreadSafeFlag.set() được viết để an toàn trong những ngữ cảnh đó. Sự đánh đổi cho sự an toàn đó là bộ tính năng nhỏ hơn so với Event: một ThreadSafeFlag chỉ có thể được chờ bởi một task tại một thời điểm, và cờ tự động reset khi task đang chờ thức dậy.
8.9.2. Dạng cơ bản¶
Một cách dùng điển hình là một ngắt GPIO chuyển sự kiện nhấn nút sang một asyncio task:
import asyncio
from machine import Pin
flag = asyncio.ThreadSafeFlag()
def on_press(pin):
flag.set()
async def watcher():
button = Pin("P1", Pin.IN, Pin.PULL_UP)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
while True:
await flag.wait()
print("button pressed")
asyncio.run(watcher())
on_press chạy trong ngữ cảnh ngắt mỗi khi GPIO kích hoạt; tất cả những gì nó làm là gọi flag.set(). Asyncio task watcher awaitflag.wait() trong một vòng lặp; mỗi khi cờ được thiết lập, task tiếp tục, chạy bất kỳ công việc nào mà nhấn nút yêu cầu, sau đó lặp lại để chờ.
8.9.3. Ba phương thức¶
set()-- đánh dấu cờ là đã thiết lập. Nếu một task hiện đang chờ trongwait(), lên lịch cho nó để tiếp tục. An toàn để gọi từ trình xử lý ngắt.wait()-- một coroutine. Chặn cho đến khi cờ được thiết lập, sau đó trả về. Cờ tự động bị xóa khi trả về -- lần gọiwaittiếp theo sẽ chặn lại cho đến lầnset()tiếp theo.clear()-- xóa cờ một cách rõ ràng mà không chờ nó. Hữu ích trước lầnwaitđầu tiên để loại bỏ bất kỳset()sớm không mong muốn nào đã kích hoạt trước khi task sẵn sàng.
8.9.4. Chỉ một waiter¶
Chỉ một task có thể đang ở trong wait() tại một thời điểm. Dạng một ứng dụng muốn là một task chủ sở hữu duy nhất cho cờ -- thường là cùng task đã cài đặt trình xử lý ngắt -- với các task khác giao tiếp với nó thông qua Event, Lock, hoặc cấu trúc dữ liệu chia sẻ được bảo vệ bởi các nguyên thủy đó.
Khi một nút phải đánh thức nhiều task, task chủ sở hữu là nơi để fan out: watcher ở trên có thể gọi some_event.set() sau mỗi lần nhấn, và tất cả các task đang chờ trên some_event sẽ tiếp tục.