Cara menggunakan asyncio di Python
Fungsi pengaturcaraan asynchronous Python, atau ringkasnya async, membolehkan anda menulis program yang menyelesaikan lebih banyak kerja dengan tidak menunggu tugas bebas selesai. The asyncio
perpustakaan termasuk dengan Python memberi anda alat untuk penggunaan async untuk memproses cakera atau rangkaian I / O tanpa membuat segala-galanya tunggu lagi.
asyncio
menyediakan dua jenis API untuk menangani operasi tak segerak: tahap tinggi dan tahap rendah . API peringkat tinggi adalah yang paling berguna, dan boleh digunakan untuk pelbagai aplikasi. API tahap rendah kuat, tetapi juga kompleks, dan jarang digunakan.
Kami akan menumpukan perhatian pada API peringkat tinggi dalam artikel ini. Pada bahagian di bawah, kita akan melihat API tahap tinggi yang paling biasa digunakan asyncio
, dan menunjukkan bagaimana ia boleh digunakan untuk operasi biasa yang melibatkan tugas tak segerak.
Sekiranya anda benar-benar baru menggunakan async di Python, atau anda boleh menggunakan penyegaran semula mengenai cara kerjanya, baca pengenalan saya mengenai Python async sebelum menyelam di sini.
Jalankan coroutine dan tugas di Python
Secara semula jadi, penggunaan yang paling biasa asyncio
adalah menjalankan bahagian asinkron skrip Python anda. Ini bermaksud belajar bekerja dengan coroutine dan tugas.
Komponen async Python, termasuk coroutine dan tugas, hanya dapat digunakan dengan komponen async lain, dan bukan dengan Python segerak konvensional, jadi anda perlu asyncio
merapatkan jurang. Untuk melakukan ini, anda menggunakan asyncio.run
fungsi:
import asyncioasync def main ():
cetak ("Menunggu 5 saat.")
untuk _ dalam jarak (5):
tunggu asyncio.sleep (1)
cetak (".")
cetak ("Selesai menunggu.")
asyncio.run (utama ())
Ini berjalan main()
, bersamaan dengan main()
kebakaran coroutine , dan menunggu hasilnya kembali.
Sebagai peraturan umum, program Python hanya boleh mempunyai satu .run()
pernyataan, sama seperti program Python hanya boleh mempunyai satu main()
fungsi. Async, jika digunakan secara cuai, dapat menjadikan aliran kawalan program sukar dibaca. Mempunyai satu titik masuk ke kod asinkron program menjadikan perkara tidak menjadi berbulu.
Fungsi async juga dapat dijadwalkan sebagai tugas , atau objek yang membungkus coroutin dan membantu menjalankannya.
async def my_task ():lakukan sesuatu()
task = asyncio.create_task (my_task ())
my_task()
kemudian dijalankan dalam gelung acara, dengan hasilnya disimpan di task
.
Sekiranya anda hanya mempunyai satu tugas yang ingin anda dapatkan hasilnya, anda boleh gunakan asyncio.wait_for(task)
untuk menunggu tugas selesai, kemudian gunakan task.result()
untuk mendapatkan hasilnya. Tetapi jika anda telah menjadualkan sejumlah tugas untuk dilaksanakan dan anda ingin menunggu semuanya selesai, gunakan asyncio.wait([task1, task2])
untuk mengumpulkan hasilnya. (Perhatikan bahawa anda boleh menetapkan batas waktu operasi jika anda tidak mahu operasi berjalan melewati jangka waktu tertentu.)
Urus gelung peristiwa tak segerak di Python
Satu lagi kegunaan biasa bagi asyncio
adalah untuk menguruskan async acara gelung . Gelung peristiwa adalah objek yang menjalankan fungsi dan panggil balik async; ia dibuat secara automatik semasa anda menggunakan asyncio.run()
. Anda biasanya ingin menggunakan hanya satu gelung peristiwa tak segerak setiap program, sekali lagi untuk memastikan semuanya dapat dikendalikan.
Sekiranya anda menulis perisian yang lebih maju, seperti pelayan, anda memerlukan akses tahap rendah ke gelung acara. Untuk itu, anda boleh "mengangkat tudung" dan bekerja secara langsung dengan bahagian dalaman gelung acara. Tetapi untuk pekerjaan sederhana anda tidak perlu.
Baca dan tulis data dengan aliran di Python
Senario terbaik untuk async adalah operasi rangkaian yang berjalan lama, di mana aplikasi mungkin menyekat menunggu beberapa sumber lain untuk menghasilkan hasil. Untuk itu, asyncio
menawarkan aliran, yang merupakan mekanisme tahap tinggi untuk melakukan I / O rangkaian. Ini termasuk bertindak sebagai pelayan untuk permintaan rangkaian.
asyncio
menggunakan dua kelas, StreamReader
dan StreamWriter
, untuk membaca dan menulis dari rangkaian pada tahap tinggi. Sekiranya anda ingin membaca dari rangkaian, anda akan menggunakan asyncio.open_connection()
untuk membuka sambungan. Fungsi itu mengembalikan tupel StreamReader
dan StreamWriter
objek, dan anda akan menggunakan .read()
dan .write()
kaedah pada masing-masing untuk berkomunikasi.
Untuk menerima sambungan dari hos jauh, gunakan asyncio.start_server()
. Yang asyncio.start_server()
fungsi mengambil sebagai hujah fungsi panggil balik, client_connected_cb
, yang dipanggil bila-bila masa ia menerima permintaan. Fungsi panggil balik itu mengambil contoh StreamReader
dan StreamWriter
sebagai argumen, sehingga anda dapat menangani logik membaca / menulis untuk pelayan. (Lihat di sini untuk contoh pelayan HTTP sederhana yang menggunakan perpustakaan asyncio
-driven aiohttp
.)
Segerakkan tugas di Python
Tugas asinkron cenderung berjalan secara terpisah, tetapi kadang-kadang anda mahu mereka berkomunikasi antara satu sama lain. asyncio
menyediakan barisan dan beberapa mekanisme lain untuk menyegerakkan antara tugas:
- Antrean :
asyncio
antrian membolehkan fungsi tak segerak untuk membariskan objek Python untuk dimakan oleh fungsi asinkron lain - misalnya, untuk mengedarkan beban kerja antara pelbagai jenis fungsi berdasarkan tingkah laku mereka. - Primitif penyegerakan : Kunci, peristiwa, keadaan, dan semafor dalam
asyncio
kerja seperti rakan-rakan Python konvensional mereka.
Satu perkara yang perlu diingat mengenai semua kaedah ini ialah kaedah ini tidak selamat. Ini bukan masalah untuk tugas asinkron yang berjalan dalam gelung peristiwa yang sama. Tetapi jika anda cuba berkongsi maklumat dengan tugas dalam gelung peristiwa, urutan OS, atau proses yang berbeza, anda perlu menggunakan threading
modul dan objeknya untuk melakukannya.
Selanjutnya, jika anda ingin melancarkan coroutine melintasi batas utas, gunakan asyncio.run_coroutine_threadsafe()
fungsinya, dan lulus gelung peristiwa untuk digunakan dengannya sebagai parameter.
Jeda coroutine di Python
Penggunaan lain yang biasa asyncio
, dan yang sedang dibincangkan, sedang menunggu masa yang sewenang-wenang di dalam coroutine. Anda tidak boleh menggunakannya time.sleep()
untuk ini, atau anda akan menyekat keseluruhan program. Sebaliknya, gunakan asyncio.sleep()
, yang membolehkan coroutine lain terus berjalan.
Gunakan async tahap bawah di Python
Akhirnya, jika anda berpendapat bahawa aplikasi yang anda bina mungkin memerlukan asyncio
komponen tingkat bawah, lihatlah sebelum anda mula membuat pengekodan: Ada kemungkinan seseorang telah membina perpustakaan Python berkuasa async yang melakukan apa yang anda perlukan.
Sebagai contoh, jika anda memerlukan pertanyaan DNS async, periksa aiodns
perpustakaan, dan untuk sesi SSH async, ada asyncSSH
. Cari PyPI dengan kata kunci "async" (ditambah kata kunci yang berkaitan dengan tugas lain), atau periksa senarai Asyncio Awesome yang dikendalikan sendiri untuk mendapatkan idea.