Rumah > pembangunan bahagian belakang > Tutorial Python > Menguasai Python's Async: Tingkatkan Prestasi Apl Anda dengan Coroutine dan Gelung Acara

Menguasai Python's Async: Tingkatkan Prestasi Apl Anda dengan Coroutine dan Gelung Acara

Barbara Streisand
Lepaskan: 2024-11-17 08:53:03
asal
508 orang telah melayarinya

Mastering Python

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}!")
Salin selepas log masuk
Salin selepas log masuk

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
Salin selepas log masuk
Salin selepas log masuk

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())
Salin selepas log masuk
Salin selepas log masuk

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())
Salin selepas log masuk
Salin selepas log masuk

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}!")
Salin selepas log masuk
Salin selepas log masuk

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
Salin selepas log masuk
Salin selepas log masuk

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())
Salin selepas log masuk
Salin selepas log masuk

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())
Salin selepas log masuk
Salin selepas log masuk

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())
Salin selepas log masuk

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.


Ciptaan Kami

Pastikan anda melihat ciptaan kami:

Pusat Pelabur | Hidup Pintar | Epos & Gema | Misteri Membingungkan | Hindutva | Pembangunan Elit | Sekolah JS


Kami berada di Medium

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!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan