8.7. Event

asyncio.Event adalah primitif sinyal paling sederhana yang disediakan modul ini. Satu coroutine mengatur sebuah event ketika sesuatu telah terjadi; sejumlah coroutine lain menunggu event tersebut diatur sebelum melanjutkan. Tidak ada payload -- sebuah event adalah boolean yang menyala dan tetap menyala sampai sesuatu membersihkannya.

8.7.1. Pola dasar

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 berjalan, mencapai await evt.wait(), dan ditangguhkan -- event dimulai dalam keadaan bersih, sehingga pemanggilan wait menyerahkan kontrol kembali ke loop. Satu detik kemudian main memanggil evt.set() dan waiter dijadwalkan untuk dilanjutkan. await asyncio.sleep(0) di akhir hanyalah yield agar loop mendapat kesempatan untuk menjalankan waiter sebelum main kembali.

8.7.2. Empat metode

  • set() -- balik event ke keadaan diatur, dan jadwalkan setiap coroutine yang saat ini diblokir pada wait() untuk dilanjutkan. Event tetap diatur sampai dibersihkan.

  • clear() -- balik event kembali ke keadaan bersih. Coroutine yang await wait() sesudahnya akan diblokir lagi.

  • wait() -- sebuah coroutine. Jika event sudah diatur, langsung kembali. Jika tidak, diblokir sampai sesuatu mengaturnya.

  • is_set() -- mengembalikan keadaan saat ini tanpa diblokir. Berguna ketika sebuah coroutine ingin memeriksa event tanpa menunggunya.

8.7.3. Beberapa waiter

Beberapa coroutine dapat await event yang sama. Ketika sesuatu memanggil set() semuanya dijadwalkan untuk dilanjutkan. Event bersifat satu-ke-banyak secara default; tidak diperlukan beberapa event untuk menyebarkan ke beberapa waiter.

8.7.4. Menggunakan ulang event

Pola umum adalah menggunakan event berulang kali -- coroutine yang berjalan sekali per sinyal -- dengan membersihkannya setelah setiap putaran:

async def worker(go):
    while True:
        await go.wait()
        do_one_unit_of_work()
        go.clear()

Produsen mengatur event setiap kali ada pekerjaan; worker membersihkannya setelah mengambil sinyal. Jika produsen mungkin mengatur event lagi sebelum worker terbangun, worker mungkin ingin menangani kasus itu (while go.is_set(): ...) sebelum membersihkan.

8.7.5. Konteks yang aman

Event tidak aman untuk memanggil set() dari dalam handler interupsi. Mekanisme yang digunakannya untuk menjadwalkan waiter mengasumsikan bahwa ia berjalan di dalam konteks event loop sendiri, yang tidak berlaku untuk interupsi. Untuk membangunkan task asyncio dari handler interupsi, ThreadSafeFlag (dibahas segera) adalah primitif yang tepat.