Pemrograman Asinkron Python: Tinjauan Singkat

Ketika berbicara tentang eksekusi program, maka “eksekusi asinkron” berarti situasi di mana program tidak menunggu selesainya proses tertentu, tetapi terus bekerja secara independen. Contoh pemrograman asinkron adalah utilitas yang, bekerja secara asinkron, menulis ke file log. Meskipun utilitas seperti itu mungkin gagal (misalnya, karena kurangnya ruang disk kosong), dalam banyak kasus ini akan berfungsi dengan benar dan dapat digunakan dalam berbagai program. Mereka akan dapat memanggilnya, memberikan data untuk direkam, dan setelah itu mereka dapat terus melakukan hal mereka sendiri.



Penggunaan mekanisme asinkron saat menulis program tertentu berarti bahwa program ini akan berjalan lebih cepat daripada tanpa menggunakan mekanisme tersebut. Pada saat yang sama, apa yang direncanakan akan diluncurkan secara tidak serempak, seperti utilitas untuk logging, harus ditulis dengan mempertimbangkan keadaan darurat akun. Sebagai contoh, sebuah utilitas untuk logging, jika ruang disk habis, cukup berhenti logging, dan tidak "crash" program utama dengan kesalahan.

Eksekusi kode asinkron biasanya melibatkan operasi kode tersebut di utas terpisah. Ini - jika kita berbicara tentang sistem dengan prosesor single-core. Pada sistem dengan prosesor multi-core, kode tersebut dapat dieksekusi dengan proses menggunakan core terpisah. Prosesor single-core pada waktu tertentu dapat membaca dan menjalankan hanya satu instruksi. Ini seperti membaca buku. Anda tidak dapat membaca dua buku sekaligus.

Jika Anda membaca buku dan orang lain memberi Anda buku lain, Anda dapat mengambil buku kedua ini dan mulai membacanya. Tetapi yang pertama harus ditunda. Eksekusi kode multi-threaded diatur pada prinsip yang sama. Dan jika beberapa salinan Anda akan membaca beberapa buku sekaligus, maka itu akan mirip dengan cara kerja sistem multiprosesor.

Jika pada prosesor single-core sangat cepat untuk beralih di antara tugas-tugas yang membutuhkan daya komputasi yang berbeda (misalnya, antara perhitungan tertentu dan membaca data dari disk), maka Anda mungkin merasa bahwa inti prosesor tunggal melakukan beberapa hal pada saat yang sama. Atau, katakanlah, ini terjadi jika Anda mencoba membuka beberapa situs di browser sekaligus. Jika browser menggunakan aliran terpisah untuk memuat setiap halaman, maka semuanya akan dilakukan jauh lebih cepat daripada jika halaman-halaman ini memuat satu per satu. Memuat halaman bukanlah tugas yang sulit, itu tidak menggunakan sumber daya sistem secara maksimal, sebagai akibatnya, peluncuran simultan dari beberapa tugas semacam itu merupakan langkah yang sangat efektif.

Pemrograman Asinkron Python


Awalnya, Python menggunakan coroutine berbasis generator untuk menyelesaikan tugas pemrograman asinkron. Kemudian, dalam Python 3.4, modul asyncio (kadang-kadang namanya ditulis sebagai async IO ), yang mengimplementasikan mekanisme pemrograman asinkron. Python 3.5 memperkenalkan konstruksi async / wait.

Untuk melakukan pengembangan asinkron dalam Python, Anda perlu berurusan dengan beberapa konsep. Ini adalah coroutine dan tugas.

Coroutine


Biasanya, coroutine adalah fungsi async. Coroutine juga bisa menjadi objek yang dikembalikan dari fungsi coroutine.

Jika, ketika mendeklarasikan suatu fungsi, ini mengindikasikan bahwa itu asinkron, maka Anda dapat memanggilnya menggunakan kata kunci await :

 await say_after(1, 'hello') 

Konstruksi seperti itu berarti bahwa program akan dieksekusi sampai menemukan ekspresi tunggu, setelah itu akan memanggil fungsi dan menghentikan eksekusi sampai pekerjaan fungsi yang disebut selesai. Setelah itu, coroutine lain juga akan dapat memulai.

Menjeda program berarti kontrol kembali ke loop acara. Saat menggunakan modul asyncio , loop acara melakukan semua tugas asinkron, melakukan I / O, dan melakukan subproses. Dalam kebanyakan kasus, tugas digunakan untuk menjalankan corutin.

Tugasnya


Tugas memungkinkan Anda untuk menjalankan coroutine dalam satu event loop. Ini menyederhanakan kontrol eksekusi dari beberapa coroutine. Berikut adalah contoh yang menggunakan coroutine dan tugas. Perhatikan bahwa entitas yang dideklarasikan menggunakan async def construct adalah coroutine. Contoh ini diambil dari dokumentasi Python resmi .

 import asyncio import time async def say_after(delay, what):    await asyncio.sleep(delay)    print(what) async def main():    task1 = asyncio.create_task(        say_after(1, 'hello'))    task2 = asyncio.create_task(        say_after(2, 'world'))    print(f"started at {time.strftime('%X')}")    #     (      #  2 .)    await task1    await task2    print(f"finished at {time.strftime('%X')}") asyncio.run(main()) 

Fungsi say_after() memiliki awalan async ; sebagai hasilnya, kami memiliki coroutine. Jika kita menyimpang sedikit dari contoh ini, kita dapat mengatakan bahwa fungsi ini dapat disebut seperti ini:

     await say_after(1, 'hello')    await say_after(2, 'world') 

Dengan pendekatan ini, bagaimanapun, coroutine dipanggil secara berurutan dan membutuhkan waktu sekitar 3 detik untuk menyelesaikannya. Dalam contoh kami, mereka diluncurkan secara kompetitif. Untuk masing-masing dari mereka tugas digunakan. Akibatnya, waktu eksekusi seluruh program adalah sekitar 2 detik. Harap perhatikan bahwa agar program seperti itu berfungsi, tidak cukup hanya mendeklarasikan fungsi main() dengan async . Dalam situasi seperti itu, Anda perlu menggunakan modul asyncio .

Jika Anda menjalankan kode contoh, teks yang mirip dengan yang berikut ini akan ditampilkan di layar:

 started at 20:19:39 hello world finished at 20:19:41 

Perhatikan bahwa cap waktu pada baris pertama dan terakhir berbeda 2 detik. Jika Anda menjalankan contoh ini dengan panggilan berurutan corutin, maka perbedaan antara cap waktu sudah 3 detik.

Contoh


Dalam contoh ini, jumlah operasi yang diperlukan untuk menghitung jumlah sepuluh elemen dari urutan angka ditentukan. Perhitungan dilakukan mulai dari akhir urutan. Fungsi rekursif dimulai dengan mendapatkan angka 10, lalu menyebut dirinya dengan angka 9 dan 8, menjumlahkan apa yang akan dikembalikan. Ini berlanjut sampai perhitungan selesai. Sebagai hasilnya, ternyata, misalnya, bahwa jumlah urutan angka dari 1 hingga 10 adalah 55. Pada saat yang sama, fungsi kami sangat tidak efisien, konstruksi time.sleep(0.1) digunakan di sini.

Berikut adalah kode fungsinya:

 import time def fib(n):    global count    count=count+1    time.sleep(0.1)    if n > 1:        return fib(n-1) + fib(n-2)    return n start=time.time() global count count = 0 result = fib(10) print(result,count) print(time.time()-start) 

Apa yang terjadi jika Anda menulis ulang kode ini menggunakan mekanisme asinkron dan menerapkan konstruk asyncio.gather , yang bertanggung jawab untuk melakukan dua tugas dan menunggu untuk menyelesaikannya?

 import asyncio,time async def fib(n):    global count    count=count+1    time.sleep(0.1)    event_loop = asyncio.get_event_loop()    if n > 1:        task1 = asyncio.create_task(fib(n-1))        task2 = asyncio.create_task(fib(n-2))        await asyncio.gather(task1,task2)        return task1.result()+task2.result()    return n 

Bahkan, contoh ini bekerja bahkan sedikit lebih lambat daripada yang sebelumnya, karena semuanya dieksekusi dalam satu utas, dan panggilan ke create_task , gather dan yang lainnya seperti itu membuat beban tambahan pada sistem. Namun, tujuan dari contoh ini adalah untuk menunjukkan kemampuan untuk bersaing dalam banyak tugas dan untuk menunggu mereka selesai.

Ringkasan


Ada situasi di mana penggunaan tugas dan corutin sangat berguna, misalnya, jika suatu program berisi campuran input-output dan perhitungan, atau jika perhitungan yang berbeda dilakukan dalam program yang sama, Anda dapat memecahkan masalah ini dengan menjalankan kode dalam kompetitif daripada dalam mode berurutan. Ini membantu mengurangi waktu yang diperlukan bagi program untuk melakukan tindakan tertentu. Namun, ini tidak memungkinkan, misalnya, untuk melakukan perhitungan secara bersamaan. Multiprocessing digunakan untuk mengatur perhitungan seperti itu. Ini adalah topik besar yang terpisah.

Pembaca yang budiman! Bagaimana Anda menulis kode Python asinkron?


Source: https://habr.com/ru/post/id475246/


All Articles