Pengaturcaraan concurrency ialah pendekatan pengaturcaraan yang menangani pelaksanaan serentak pelbagai tugas. Dalam Python, asyncio ialah alat yang berkuasa untuk melaksanakan pengaturcaraan tak segerak. Berdasarkan konsep coroutine, asyncio boleh mengendalikan tugas intensif I/O dengan cekap. Artikel ini akan memperkenalkan prinsip asas dan penggunaan asyncio.
Kami tahu bahawa apabila mengendalikan operasi I/O, menggunakan multithreading boleh meningkatkan kecekapan berbanding dengan satu utas biasa. Jadi, mengapa kita masih memerlukan asyncio?
Multithreading mempunyai banyak kelebihan dan digunakan secara meluas, tetapi ia juga mempunyai batasan tertentu:
Tepatnya untuk menyelesaikan masalah inilah asyncio muncul.
Mari kita bezakan dahulu antara konsep Sync (synchronous) dan Async (asynchronous).
Ringkasnya, prinsip kerja asyncio adalah berdasarkan mekanisme coroutine dan gelung peristiwa. Dengan menggunakan coroutine untuk operasi tak segerak dan mempunyai gelung peristiwa yang bertanggungjawab untuk penjadualan dan pelaksanaan coroutine, asyncio merealisasikan model pengaturcaraan tak segerak yang cekap.
Coroutine ialah konsep penting dalam asyncio. Ia adalah unit pelaksanaan ringan yang boleh bertukar dengan cepat antara tugas tanpa overhed penukaran benang. Coroutine boleh ditakrifkan dengan kata kunci async dan kata kunci await digunakan untuk menjeda pelaksanaan coroutine dan menyambung semula selepas operasi tertentu selesai.
Berikut ialah contoh kod ringkas yang menunjukkan cara menggunakan coroutine untuk pengaturcaraan tak segerak:
import asyncio async def hello(): print("Hello") await asyncio.sleep(1) # Simulate a time-consuming operation print("World") # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(hello())
Dalam contoh ini, fungsi hello() ialah coroutine yang ditakrifkan dengan kata kunci async. Di dalam coroutine, kita boleh menggunakan await untuk menjeda pelaksanaannya. Di sini, asyncio.sleep(1) digunakan untuk mensimulasikan operasi yang memakan masa. Kaedah run_until_complete() menambahkan coroutine pada gelung acara dan menjalankannya.
asyncio digunakan terutamanya untuk mengendalikan tugas intensif I/O, seperti permintaan rangkaian, membaca fail dan menulis. Ia menyediakan satu siri API untuk operasi I/O tak segerak, yang boleh digunakan dalam kombinasi dengan kata kunci tunggu untuk mencapai pengaturcaraan tak segerak dengan mudah.
Berikut ialah contoh kod ringkas yang menunjukkan cara menggunakan asyncio untuk permintaan rangkaian tak segerak:
import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://www.example.com') print(html) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
Dalam contoh ini, kami menggunakan perpustakaan aiohttp untuk permintaan rangkaian. Fungsi fetch() ialah coroutine. Ia memulakan permintaan GET tak segerak melalui kaedah session.get() dan menunggu respons kembali menggunakan kata kunci await. Fungsi main() ialah coroutine lain. Ia mencipta objek ClientSession di dalam untuk digunakan semula, kemudian memanggil kaedah fetch() untuk mendapatkan kandungan halaman web dan mencetaknya.
Nota: Di sini kami menggunakan aiohttp dan bukannya perpustakaan permintaan kerana perpustakaan permintaan tidak serasi dengan asyncio, manakala perpustakaan aiohttp adalah. Untuk menggunakan asyncio dengan baik, terutamanya untuk melaksanakan fungsinya yang berkuasa, dalam banyak kes, perpustakaan Python yang sepadan diperlukan.
asyncio juga menyediakan beberapa mekanisme untuk melaksanakan berbilang tugas secara serentak, seperti asyncio.gather() dan asyncio.wait(). Berikut ialah kod sampel yang menunjukkan cara menggunakan mekanisme ini untuk melaksanakan berbilang tugas coroutine secara serentak:
import asyncio async def task1(): print("Task 1 started") await asyncio.sleep(1) print("Task 1 finished") async def task2(): print("Task 2 started") await asyncio.sleep(2) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
Dalam contoh ini, kami mentakrifkan dua tugas coroutine task1() dan task2(), yang kedua-duanya melakukan beberapa operasi yang memakan masa. Coroutine main() memulakan kedua-dua tugasan ini secara serentak melalui asyncio.gather() dan menunggunya selesai. Pelaksanaan serentak boleh meningkatkan kecekapan pelaksanaan program.
Dalam projek sebenar, patutkah kita memilih multithreading atau asyncio? Satu pukulan besar meringkaskannya dengan jelas:
import asyncio async def hello(): print("Hello") await asyncio.sleep(1) # Simulate a time-consuming operation print("World") # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(hello())
Masukkan senarai. Untuk setiap elemen dalam senarai, kami ingin mengira jumlah kuasa dua semua integer daripada 0 hingga elemen ini.
import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://www.example.com') print(html) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
Masa pelaksanaan ialah Pengiraan mengambil masa 16.00943413000002 saat
import asyncio async def task1(): print("Task 1 started") await asyncio.sleep(1) print("Task 1 finished") async def task2(): print("Task 2 started") await asyncio.sleep(2) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
Masa pelaksanaan ialah Pengiraan mengambil masa 7.314132894999999 saat
Dalam kod yang dipertingkatkan ini, kami menggunakan concurrent.futures.ProcessPoolExecutor untuk mencipta kumpulan proses dan kemudian menggunakan kaedah executor.map() untuk menyerahkan tugasan dan mendapatkan hasil. Ambil perhatian bahawa selepas menggunakan executor.map(), jika anda perlu mendapatkan keputusan, anda boleh mengulangi keputusan ke dalam senarai atau menggunakan kaedah lain untuk memproses keputusan.
if io_bound: if io_slow: print('Use Asyncio') else: print('Use multi-threading') elif cpu_bound: print('Use multi-processing')
Masa pelaksanaan ialah Pengiraan mengambil masa 5.024221667 saat
concurrent.futures.ProcessPoolExecutor dan multiprocessing adalah kedua-dua perpustakaan untuk melaksanakan konkurensi berbilang proses dalam Python. Terdapat beberapa perbezaan:
Ringkasnya, concurrent.futures.ProcessPoolExecutor ialah antara muka peringkat tinggi yang merangkumi fungsi berbilang proses asas, sesuai untuk penyelarasan tugas berbilang proses yang mudah. multiprocessing ialah perpustakaan peringkat rendah, memberikan lebih kawalan dan fleksibiliti, sesuai untuk senario yang memerlukan kawalan proses yang terperinci. Anda perlu memilih perpustakaan yang sesuai mengikut keperluan khusus. Jika ia hanya penyelarasan tugasan mudah, anda boleh menggunakan concurrent.futures.ProcessPoolExecutor untuk memudahkan kod; jika lebih banyak kawalan dan komunikasi tahap rendah diperlukan, anda boleh menggunakan perpustakaan berbilang pemprosesan.
Tidak seperti multithreading, asyncio adalah single-threading, tetapi mekanisme gelung peristiwa dalamannya membolehkannya menjalankan berbilang tugas yang berbeza secara serentak dan mempunyai kawalan autonomi yang lebih besar daripada multithreading.
Tugas dalam asyncio tidak akan terganggu semasa operasi, jadi situasi keadaan perlumbaan tidak akan berlaku.
Terutama dalam senario dengan operasi I/O yang berat, asyncio mempunyai kecekapan operasi yang lebih tinggi daripada multithreading. Kerana kos penukaran tugasan dalam asyncio jauh lebih kecil daripada penukaran benang dan bilangan tugasan yang boleh dimulakan oleh asyncio adalah jauh lebih besar daripada bilangan utas dalam berbilang benang.
Walau bagaimanapun, perlu diingatkan bahawa dalam banyak kes, menggunakan asyncio memerlukan sokongan perpustakaan pihak ketiga tertentu, seperti aiohttp dalam contoh sebelumnya. Dan jika operasi I/O adalah pantas dan tidak berat, menggunakan multithreading juga boleh menyelesaikan masalah dengan berkesan.
Akhir sekali, izinkan saya memperkenalkan platform yang ideal untuk menggunakan Flask/FastAPI: Leapcell.
Leapcell ialah platform pengkomputeran awan yang direka khusus untuk aplikasi pengedaran moden. Model penetapan harga bayar semasa anda memastikan tiada kos terbiar, bermakna pengguna hanya membayar untuk sumber yang sebenarnya mereka gunakan.
Ketahui lebih lanjut dalam dokumentasi!
Twitter Leapcell: https://x.com/LeapcellHQ
Atas ialah kandungan terperinci Python Berprestasi Tinggi: Asyncio. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!