Pengaturcaraan async Python ialah pengubah permainan untuk membina aplikasi berprestasi tinggi. Saya telah menggunakannya selama bertahun-tahun, dan ia tidak pernah berhenti memukau saya betapa hebatnya ia apabila digunakan dengan betul.
Di tengah-tengah model async Python ialah coroutine dan gelung peristiwa. Coroutine ialah fungsi khas yang boleh menjeda dan menyambung semula pelaksanaannya, membolehkan multitasking yang cekap tanpa overhed benang. Gelung peristiwa, sebaliknya, adalah enjin yang memacu coroutine ini, mengurus pelaksanaannya dan mengendalikan operasi I/O.
Mari kita mulakan dengan coroutine. Dalam Python, kami mentakrifkannya menggunakan sintaks async def. Berikut ialah contoh mudah:
async def greet(name): print(f"Hello, {name}!") await asyncio.sleep(1) print(f"Goodbye, {name}!")
Coroutine ini menyapa seseorang, menunggu sebentar, dan kemudian mengucapkan selamat tinggal. Kata kunci tunggu adalah penting di sini - ia membenarkan coroutine menjeda pelaksanaannya dan memberikan kawalan kembali kepada gelung acara.
Tetapi bagaimanakah coroutine berfungsi di bawah tudung? Mereka sebenarnya dibina di atas fungsi penjana Python. Apabila anda memanggil coroutine, ia tidak akan berjalan serta-merta. Sebaliknya, ia mengembalikan objek coroutine. Objek ini boleh menghantar nilai dan boleh menghasilkan nilai, sama seperti penjana.
Gelung acara bertanggungjawab untuk menjalankan coroutine ini sebenarnya. Ia mengekalkan baris gilir tugas (yang merupakan pembalut di sekeliling coroutine) dan melaksanakannya satu demi satu. Apabila coroutine mencecah pernyataan menunggu, gelung acara menggantungnya dan beralih ke tugas seterusnya. Inilah intipati multitasking koperasi - tugas secara sukarela melepaskan kawalan, membenarkan orang lain menjalankan.
Berikut ialah versi ringkas tentang cara gelung acara mungkin berfungsi:
class EventLoop: def __init__(self): self.ready = deque() self.sleeping = [] def call_soon(self, callback): self.ready.append(callback) def call_later(self, delay, callback): deadline = time.time() + delay heapq.heappush(self.sleeping, (deadline, callback)) def run_forever(self): while True: self.run_once() def run_once(self): now = time.time() while self.sleeping and self.sleeping[0][0] <= now: _, callback = heapq.heappop(self.sleeping) self.ready.append(callback) if self.ready: callback = self.ready.popleft() callback() else: time.sleep(0.1) # Avoid busy waiting
Gelung acara ini menguruskan dua jenis tugasan: tugasan yang sedia untuk dijalankan (dalam deque sedia) dan tugasan yang sedang tidur (dalam senarai tidur). Kaedah run_forever terus menjalankan tugas sehingga tiada lagi yang tinggal.
Sekarang, mari kita bincangkan tentang penjadualan tugas. Modul asyncio dalam Python menyediakan gelung acara yang lebih canggih dengan keupayaan penjadualan lanjutan. Ia boleh mengendalikan operasi I/O, menjalankan subproses dan juga berintegrasi dengan gelung peristiwa lain.
Begini cara anda boleh menggunakan asyncio untuk menjalankan berbilang coroutine serentak:
import asyncio async def task1(): print("Task 1 starting") await asyncio.sleep(2) print("Task 1 finished") async def task2(): print("Task 2 starting") await asyncio.sleep(1) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) asyncio.run(main())
Skrip ini akan memulakan kedua-dua tugas, tetapi tugas2 akan selesai sebelum tugas1 kerana ia tidur untuk masa yang lebih singkat.
Salah satu aplikasi pengaturcaraan async yang paling berkuasa ialah dalam operasi rangkaian. Mari lihat pelayan web tak segerak yang ringkas:
import asyncio async def handle_client(reader, writer): data = await reader.read(100) message = data.decode() addr = writer.get_extra_info('peername') print(f"Received {message!r} from {addr!r}") response = f"Echo: {message}\n" writer.write(response.encode()) await writer.drain() print("Close the connection") writer.close() async def main(): server = await asyncio.start_server( handle_client, '127.0.0.1', 8888) addr = server.sockets[0].getsockname() print(f'Serving on {addr}') async with server: await server.serve_forever() asyncio.run(main())
Pelayan ini boleh mengendalikan berbilang pelanggan serentak tanpa menggunakan benang, menjadikannya sangat cekap.
Tetapi pengaturcaraan async bukan hanya untuk pelayan. Ia juga bagus untuk pelanggan, terutamanya apabila anda perlu membuat berbilang permintaan rangkaian. Berikut ialah pengikis web ringkas yang boleh mengambil berbilang halaman serentak:
async def greet(name): print(f"Hello, {name}!") await asyncio.sleep(1) print(f"Goodbye, {name}!")
Pengikis ini boleh mengambil berbilang halaman serentak, mempercepatkan proses dengan ketara berbanding pendekatan segerak.
Sekarang, mari kita selami beberapa konsep yang lebih maju. Satu ciri menarik model async Python ialah anda boleh membuat gelung acara anda sendiri. Ini boleh berguna jika anda perlu menyepadukan kod async dengan rangka kerja lain atau jika anda mahu mengoptimumkan untuk kes penggunaan tertentu.
Berikut ialah gelung acara tersuai ringkas yang boleh menjalankan panggilan balik segerak dan tak segerak:
class EventLoop: def __init__(self): self.ready = deque() self.sleeping = [] def call_soon(self, callback): self.ready.append(callback) def call_later(self, delay, callback): deadline = time.time() + delay heapq.heappush(self.sleeping, (deadline, callback)) def run_forever(self): while True: self.run_once() def run_once(self): now = time.time() while self.sleeping and self.sleeping[0][0] <= now: _, callback = heapq.heappop(self.sleeping) self.ready.append(callback) if self.ready: callback = self.ready.popleft() callback() else: time.sleep(0.1) # Avoid busy waiting
Gelung tersuai ini sangat asas, tetapi ia menunjukkan prinsip teras. Anda boleh melanjutkan ini untuk mengendalikan senario yang lebih kompleks, seperti operasi I/O atau pemasa.
Menyahpepijat kod async mungkin mencabar, terutamanya apabila anda berurusan dengan aplikasi yang kompleks. Satu teknik yang saya rasa berguna ialah menggunakan mod nyahpepijat asyncio. Anda boleh mendayakannya seperti ini:
import asyncio async def task1(): print("Task 1 starting") await asyncio.sleep(2) print("Task 1 finished") async def task2(): print("Task 2 starting") await asyncio.sleep(1) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) asyncio.run(main())
Ini akan memberikan mesej ralat dan amaran yang lebih terperinci tentang perkara seperti coroutine yang tidak pernah selesai atau panggilan balik yang mengambil masa terlalu lama untuk dijalankan.
Satu lagi teknik nyahpepijat berguna ialah menggunakan ciri introspeksi tugas asyncio. Sebagai contoh, anda boleh mendapatkan senarai semua tugasan yang sedang dijalankan:
import asyncio async def handle_client(reader, writer): data = await reader.read(100) message = data.decode() addr = writer.get_extra_info('peername') print(f"Received {message!r} from {addr!r}") response = f"Echo: {message}\n" writer.write(response.encode()) await writer.drain() print("Close the connection") writer.close() async def main(): server = await asyncio.start_server( handle_client, '127.0.0.1', 8888) addr = server.sockets[0].getsockname() print(f'Serving on {addr}') async with server: await server.serve_forever() asyncio.run(main())
Ini boleh membantu anda memahami apa yang program anda lakukan pada bila-bila masa.
Apabila ia datang untuk mengoptimumkan kod async, satu prinsip utama ialah meminimumkan masa yang dibelanjakan dalam operasi segerak. Sebarang kod segerak yang berjalan lama akan menyekat gelung acara, menghalang coroutine lain daripada dijalankan. Jika anda mempunyai tugasan intensif CPU, pertimbangkan untuk menjalankannya dalam urutan atau proses yang berasingan.
Satu lagi teknik pengoptimuman ialah menggunakan asyncio.gather apabila anda mempunyai berbilang coroutine yang boleh dijalankan serentak. Ini lebih cekap daripada menunggu mereka satu persatu:
import asyncio import aiohttp async def fetch_page(session, url): async with session.get(url) as response: return await response.text() async def main(): urls = [ 'http://example.com', 'http://example.org', 'http://example.net' ] async with aiohttp.ClientSession() as session: tasks = [fetch_page(session, url) for url in urls] pages = await asyncio.gather(*tasks) for url, page in zip(urls, pages): print(f"Page from {url}: {len(page)} bytes") asyncio.run(main())
Akhir sekali, ingat bahawa pengaturcaraan async bukanlah penyelesaian terbaik. Untuk tugas terikat I/O dengan banyak menunggu, ia boleh memberikan peningkatan prestasi yang ketara. Tetapi untuk tugasan terikat CPU, multithreading tradisional atau multiprocessing mungkin lebih sesuai.
Kesimpulannya, model pengaturcaraan async Python, dibina pada coroutine dan gelung acara, menawarkan cara yang berkesan untuk menulis aplikasi yang cekap dan berskala. Sama ada anda sedang membina pelayan web, pelanggan rangkaian atau saluran paip pemprosesan data, memahami konsep ini boleh membantu anda memanfaatkan sepenuhnya keupayaan async Python. Seperti mana-mana alat yang berkuasa, ia memerlukan latihan dan pemikiran yang teliti untuk digunakan dengan berkesan, tetapi hasilnya boleh benar-benar mengagumkan.
Pastikan anda melihat ciptaan kami:
Pusat Pelabur | Hidup Pintar | Epos & Gema | Misteri Membingungkan | Hindutva | Pembangunan Elit | Sekolah JS
Tech Koala Insights | Dunia Epok & Gema | Medium Pusat Pelabur | Medium Misteri Membingungkan | Sains & Zaman Sederhana | Hindutva Moden
Atas ialah kandungan terperinci Menguasai Python's Async: Tingkatkan Prestasi Apl Anda dengan Coroutine dan Gelung Acara. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!