8.9. ThreadSafeFlag¶
asyncio.ThreadSafeFlag adalah primitif sinyal yang disediakan asyncio untuk kasus yang tidak didukung oleh Event: handler interupsi perlu membangunkan task asyncio. Interupsi terjadi di luar penjadwalan normal event loop, sehingga pembukuan yang dilakukan asyncio.Event.set() tidak dapat dilakukan dengan aman dari dalamnya.
8.9.1. Mengapa primitif terpisah¶
asyncio.Event.set() menjalankan pembukuan yang membangunkan coroutine yang menunggu dengan asumsi bahwa ia dipanggil dari dalam task yang sedang dijalankan oleh loop. Handler interupsi tidak memenuhi asumsi tersebut -- ia dapat terjadi di antara dua instruksi mana pun dan merusak apa pun yang sedang dikerjakan loop.
asyncio.ThreadSafeFlag.set() ditulis agar aman dalam konteks tersebut. Pertukaran untuk keamanan tersebut adalah kumpulan fitur yang lebih kecil dari Event: sebuah ThreadSafeFlag hanya dapat ditunggu oleh satu task pada satu waktu, dan flag direset otomatis ketika task yang menunggu terbangun.
8.9.2. Pola dasar¶
Penggunaan khas adalah interupsi GPIO yang meneruskan event penekanan tombol ke task asyncio:
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 berjalan dalam konteks interupsi setiap kali GPIO terjadi; semua yang dilakukannya adalah memanggil flag.set(). Task asyncio watcher awaits flag.wait() dalam loop; setiap kali flag diatur, task dilanjutkan, menjalankan pekerjaan apa pun yang diperlukan oleh penekanan tombol, kemudian kembali ke loop untuk menunggu lagi.
8.9.3. Tiga metode¶
set()-- tandai flag sebagai diatur. Jika sebuah task saat ini sedang menunggu dalamwait(), jadwalkan untuk dilanjutkan. Aman untuk dipanggil dari handler interupsi.wait()-- sebuah coroutine. Diblokir sampai flag diatur, kemudian kembali. Flag dibersihkan secara otomatis saat kembali -- pemanggilanwaitberikutnya akan diblokir lagi sampaiset()berikutnya.clear()-- bersihkan flag secara eksplisit tanpa menunggunya. Berguna sebelumwaitpertama untuk membuang pemanggilanset()awal yang berlebihan yang terjadi sebelum task siap.
8.9.4. Hanya satu waiter¶
Hanya satu task yang dapat berada dalam wait() pada satu waktu. Pola yang diinginkan aplikasi adalah satu task pemilik tunggal untuk flag -- biasanya task yang sama yang memasang handler interupsi -- dengan task lain berkomunikasi dengannya melalui Event, Lock, atau struktur data bersama yang dilindungi oleh primitif tersebut.
Ketika sebuah tombol harus membangunkan beberapa task, task pemilik adalah tempat untuk menyebarkan: watcher di atas dapat memanggil some_event.set() setelah setiap penekanan, dan semua task yang menunggu some_event akan dilanjutkan.