Cara menggunakan asyncio dengan Python

Fungsionalitas pemrograman asinkron Python, atau singkatnya async, memungkinkan Anda menulis program yang menyelesaikan lebih banyak pekerjaan dengan tidak menunggu tugas independen selesai. The asyncioperpustakaan disertakan dengan Python memberi Anda alat untuk digunakan async untuk memproses disk atau jaringan I / O tanpa membuat segala sesuatu yang lain menunggu.

asyncio menyediakan dua jenis API untuk menangani operasi asinkron:  level tinggi  dan  level rendah . API tingkat tinggi adalah yang paling berguna secara umum, dan dapat diterapkan ke berbagai aplikasi terluas. API level rendah sangat kuat, tetapi juga kompleks, dan lebih jarang digunakan.

Kami akan berkonsentrasi pada API tingkat tinggi di artikel ini. Pada bagian di bawah ini, kita akan membahas API tingkat tinggi yang paling umum digunakan di asyncio, dan menunjukkan bagaimana API tersebut  dapat digunakan untuk operasi umum yang melibatkan tugas-tugas asinkron. 

Jika Anda benar-benar baru mengenal asinkron dengan Python, atau Anda dapat menggunakan penyegar tentang cara kerjanya, baca pengantar saya tentang asinkron Python sebelum menyelam di sini.

Jalankan coroutine dan tugas dengan Python

Secara alami, penggunaan paling umum untuk asyncioadalah menjalankan bagian asinkron dari skrip Python Anda. Ini berarti belajar bekerja dengan coroutine dan tugas. 

Komponen asinkron Python, termasuk coroutine dan tugas, hanya dapat digunakan dengan komponen asinkron lainnya, dan tidak dengan Python sinkron konvensional, jadi Anda perlu  asyncio menjembatani kesenjangan tersebut. Untuk melakukan ini, Anda menggunakan  asyncio.run fungsi:

impor asyncio

async def main ():

print ("Menunggu 5 detik.")

untuk _ dalam rentang (5):

menunggu asyncio.sleep (1)

cetak (".")

print ("Selesai menunggu.")

asyncio.run (main ())

Ini berjalan  main(), bersama dengan coroutine apa pun yang  main() diaktifkan, dan menunggu hasil ditampilkan.

Sebagai aturan umum, program Python hanya boleh memiliki satu  .run() pernyataan, sama seperti program Python hanya memiliki satu  main() fungsi. Asinkron, jika digunakan secara sembarangan, dapat membuat aliran kontrol program sulit dibaca. Memiliki satu titik masuk ke kode asinkron program mencegah hal-hal menjadi rumit.

Fungsi asinkron juga dapat dijadwalkan sebagai  tugas , atau objek yang membungkus coroutine dan membantu menjalankannya.

async def my_task ():

lakukan sesuatu()

task = asyncio.create_task (my_task ())

my_task() kemudian dijalankan di loop acara, dengan hasilnya disimpan di  task.

Jika Anda hanya memiliki satu tugas yang ingin Anda peroleh hasilnya, Anda dapat menggunakan  asyncio.wait_for(task) untuk menunggu tugas tersebut selesai, lalu gunakan  task.result() untuk mengambil hasilnya. Tetapi jika Anda telah menjadwalkan sejumlah tugas untuk dijalankan dan Anda ingin menunggu  semuanya  selesai, gunakan  asyncio.wait([task1, task2]) untuk mengumpulkan hasilnya. (Perhatikan bahwa Anda dapat menyetel waktu tunggu untuk operasi jika Anda tidak ingin operasi tersebut melewati jangka waktu tertentu.)

Kelola event loop async dengan Python

Penggunaan umum lainnya untuk  asyncio adalah untuk mengelola loop peristiwa asinkron  . Perulangan peristiwa adalah objek yang menjalankan fungsi asinkron dan callback; itu dibuat secara otomatis saat Anda menggunakan  asyncio.run(). Biasanya Anda hanya ingin menggunakan satu loop kejadian asinkron per program, sekali lagi untuk menjaga agar semuanya dapat dikelola.

Jika Anda menulis perangkat lunak yang lebih canggih, seperti server, Anda memerlukan akses tingkat yang lebih rendah ke loop acara. Untuk itu, Anda dapat "mengangkat penutup" dan bekerja secara langsung dengan internal loop acara. Tetapi untuk pekerjaan sederhana Anda tidak perlu melakukannya.

Membaca dan menulis data dengan aliran dengan Python

Skenario terbaik untuk asinkron adalah operasi jaringan yang berjalan lama, di mana aplikasi mungkin memblokir menunggu sumber daya lain untuk mengembalikan hasil. Untuk itu,  asyncio menawarkan aliran, yang merupakan mekanisme tingkat tinggi untuk melakukan I / O jaringan. Ini termasuk bertindak sebagai server untuk permintaan jaringan.

asyncio menggunakan dua kelas,  StreamReader dan  StreamWriter, untuk membaca dan menulis dari jaringan pada tingkat tinggi. Jika Anda ingin membaca dari jaringan, Anda akan menggunakannya  asyncio.open_connection() untuk membuka koneksi. Fungsi itu mengembalikan tupel  StreamReader dan  StreamWriter objek, dan Anda akan menggunakan   metode .read() dan  .write()pada masing-masing untuk berkomunikasi.

Untuk menerima koneksi dari host jarak jauh, gunakan  asyncio.start_server(). The asyncio.start_server()Fungsi mengambil sebagai argumen fungsi callback,  client_connected_cbyang disebut setiap kali menerima permintaan. Fungsi callback tersebut mengambil instance dari  StreamReader dan StreamWriter sebagai argumen, sehingga Anda dapat menangani logika baca / tulis untuk server. (Lihat di sini untuk contoh server HTTP sederhana yang menggunakan   pustaka asyncio-driven  aiohttp.)

Sinkronkan tugas dengan Python

Tugas asinkron cenderung berjalan secara terpisah, tetapi terkadang Anda ingin tugas tersebut saling berkomunikasi. asyncio menyediakan antrian dan beberapa mekanisme lain untuk sinkronisasi antar tugas:

  • Antrianasyncio antrian memungkinkan fungsi asinkron untuk menyusun objek Python untuk digunakan oleh fungsi asinkron lainnya - misalnya, untuk mendistribusikan beban kerja antara berbagai jenis fungsi berdasarkan perilakunya.
  • Primitif sinkronisasi : Kunci, peristiwa, kondisi, dan semaphore dalam asynciopekerjaan seperti rekan Python konvensional mereka. 

Satu hal yang perlu diingat tentang semua metode ini adalah metode ini  tidak  aman untuk thread. Ini bukan masalah untuk tugas asinkron yang berjalan di loop acara yang sama. Tetapi jika Anda mencoba berbagi informasi dengan tugas di loop peristiwa, utas OS, atau proses yang berbeda, Anda harus menggunakan  threading modul dan objeknya untuk melakukan itu.

Lebih lanjut, jika Anda ingin  meluncurkan  coroutine melintasi batas thread, gunakan  asyncio.run_coroutine_threadsafe() fungsinya, dan teruskan loop peristiwa untuk digunakan dengannya sebagai parameter.

Jeda coroutine dengan Python

Penggunaan umum lainnya  asyncio, dan yang masih belum dibahas, adalah menunggu beberapa lama waktu yang berubah-ubah di dalam coroutine. Anda tidak dapat menggunakan  time.sleep() untuk ini, atau Anda akan memblokir seluruh program. Sebaliknya, gunakan  asyncio.sleep(), yang memungkinkan coroutine lain untuk terus berjalan.

Gunakan asinkron tingkat rendah dengan Python

Terakhir, jika Anda berpikir bahwa aplikasi yang Anda buat mungkin memerlukan asynciokomponen tingkat yang lebih rendah, lihat-lihat sebelum Anda memulai pengkodean: Ada kemungkinan besar seseorang telah membangun pustaka Python yang didukung asinkron yang melakukan apa yang Anda butuhkan.

Misalnya, jika Anda memerlukan kueri DNS asinkron, periksa  aiodns pustaka, dan untuk sesi SSH asinkron, ada  asyncSSH. Cari PyPI dengan kata kunci "async" (ditambah kata kunci terkait tugas lainnya), atau periksa daftar Awesome Asyncio yang dikurasi sendiri untuk mendapatkan ide.