2.32. Coroutine¶
Sebuah coroutine adalah fungsi yang dapat berhenti di tengah eksekusi dan dilanjutkan kembali dari titik yang sama, dengan semua variabel lokalnya tetap utuh. Ini mencerminkan pola generator -- sebuah badan fungsi yang dapat ditangguhkan dan dilanjutkan -- dengan satu perbedaan: siapa yang mengendalikan setiap pelanjutan.
Sintaks Python untuk menulis coroutine adalah pasangan kata kunci async / await. async menandai fungsi sebagai coroutine; await menandai titik-titik di dalamnya di mana penghentian sementara diizinkan.
2.32.1. Mendefinisikan coroutine¶
Fungsi yang didefinisikan dengan async def adalah fungsi coroutine. Memanggilnya tidak menjalankan badan fungsinya; melainkan mengembalikan objek coroutine yang belum dimulai:
async def greet(name):
print("hello,", name)
coro = greet("Alice") # body NOT run yet
Objek coroutine ditangguhkan di awal fungsi. Sesuatu harus mengendalikan coroutine agar badannya berjalan -- sesuatu itu adalah event loop, sebuah komponen runtime. MicroPython menyertakannya dalam modul asyncio. Untuk saat ini, anggap coroutine sebagai "siap dijalankan, menunggu pengendali".
2.32.2. Menghentikan sementara di dalam coroutine¶
Di dalam coroutine, ekspresi await menangguhkan eksekusi hingga nilai yang ditunggu siap:
async def fetch_and_log():
data = await read_sensor()
print("got:", data)
Ketika badan fungsi mencapai await read_sensor(), coroutine menyerahkan kendali kembali ke apapun yang menjalankannya. Ketika read_sensor() selesai, pengendali melanjutkan coroutine di baris berikutnya, dengan hasilnya terikat ke data.
await hanya berlaku di dalam coroutine. Menggunakannya dalam fungsi biasa adalah kesalahan sintaks.
2.32.3. Hubungan dengan generator¶
Coroutine dan generator berbagi mekanisme dasar yang sama. Perbedaannya adalah siapa yang menarik setiap pelanjutan:
Generator menghasilkan nilai; konsumen menarik nilai berikutnya dengan
next()atau dengan melakukan iterasi.Coroutine menghasilkan kendali; event loop menjadwalkan pelanjutan ketika operasi yang ditunggu siap.
Jika jabat tangan generator-yield sudah dipahami, jabat tangan coroutine adalah ide yang sama -- hanya dikendalikan oleh event loop, bukan loop for.
Sebuah event loop adalah dispatcher kecil yang menyimpan daftar coroutine yang menunggu sesuatu (timer, event jaringan, coroutine lain yang selesai). Setiap iterasi, ia memilih coroutine yang penantiannya telah terpenuhi, melanjutkannya hingga await berikutnya, lalu mencatat apa yang coroutine itu tunggu sekarang dan beralih ke coroutine lain yang siap. Hasilnya adalah banyak task yang membuat kemajuan secara bersamaan dalam satu thread -- setiap coroutine secara sukarela menyerahkan kendali di titik-titik await-nya, dan loop mengisi momen-momen itu dengan coroutine lain yang siap membuat kemajuan.
Di balik layar, await dan yield menggunakan fitur runtime Python yang sama untuk menangguhkan dan melanjutkan fungsi. Kata kunci berbeda karena konvensi di sekitarnya berbeda: yield menyerahkan nilai kembali ke konsumen yang menarik dengan next(); await menyerahkan kendali ke event loop yang menjadwalkan pelanjutan ketika operasi yang ditunggu siap. async / await pada dasarnya adalah sintaks yang lebih baru untuk pola coroutine -- pustaka lama membangun coroutine di atas mekanisme generator secara langsung, menggunakan yield from (diperkenalkan di Iterator dan generator) untuk mendelegasikan penangguhan antar coroutine.
2.32.4. Coroutine membutuhkan pengendali¶
Sebuah coroutine tidak aktif tanpa runtime untuk mengendalikannya. Mendefinisikannya tidak masalah; menjalankannya membutuhkan event loop. Modul asyncio MicroPython menyediakan event loop tersebut. Bagian Asyncio membahas cara memulai loop, menjadwalkan coroutine di dalamnya, berbagi state antar coroutine dengan lock dan event, menangani pembatalan dan timeout, serta menyusun aplikasi nyata berdasarkan kata kunci async / await yang diperkenalkan di sini.