Python Academy · Oppitunti

Asynkronisen I/O:n mallit tuotannossa

Soveltakaa asyncioa HTTP-asiakkaisiin, jonoihin ja tosielämän käsittelyputkiin.

Oppitunti 4/413 vaihetta

Asynkronisen I/O:n mallit tuotannossa on ilmainen Python Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Python Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Python Academy-kurssilla on yhteensä 4 oppituntia.

Tapahtumasilmukan parhaat käytännöt

Käytä aina asyncio.run()-funktiota ainoana aloituspisteenä. Vältä synkronisen ja asynkronisen koodin huolimatonta sekoittamista, äläkä koskaan estä tapahtumasilmukkaa pitkään kestävällä suorittimella tehtävällä työllä.

import asyncio

async def main():
    # Never: time.sleep() — blocks the event loop
    # Always: await asyncio.sleep()
    await asyncio.sleep(1)

asyncio.run(main())

Yhteyksien poolaus

Käytä yhteyksiä uudelleen sen sijaan, että avaisit uuden yhteyden jokaista pyyntöä varten. Kirjastot, kuten asyncpg ja aiohttp, tarjoavat sisäänrakennetut yhteyspoolit.

# pip install asyncpg
import asyncpg, asyncio

async def main():
    pool = await asyncpg.create_pool(
        dsn="postgresql://user:pass@host/db",
        min_size=5, max_size=20
    )
    async with pool.acquire() as conn:
        row = await conn.fetchrow("SELECT 1")
    await pool.close()

Tuottaja–kuluttaja asyncio.Queuella

asyncio.Queue irrottaa samanaikaisina tehtävinä suoritettavat tuottajat ja kuluttajat toisistaan.

import asyncio

async def producer(q):
    for i in range(5):
        await q.put(i)
        await asyncio.sleep(0.5)
    await q.put(None)  # sentinel

async def consumer(q):
    while (item := await q.get()) is not None:
        print(f"processing {item}")
        q.task_done()

async def main():
    q = asyncio.Queue()
    await asyncio.gather(producer(q), consumer(q))

asyncio.run(main())

Nopeusrajoitus semaforilla

Rajoita samanaikaisten lähtevien pyyntöjen määrää, jotta ulkoiset API:t eivät kuormitu liikaa etkä ylitä niiden nopeusrajoja.

import asyncio, aiohttp

SEM = asyncio.Semaphore(10)  # 10 concurrent requests max

async def fetch(session, url):
    async with SEM:
        async with session.get(url) as r:
            return await r.json()

async def main(urls):
    async with aiohttp.ClientSession() as s:
        return await asyncio.gather(*[fetch(s, u) for u in urls])

Uudelleenyritys eksponentiaalisella backoffilla

Kääri uudelleenyritykseen soveltuvat toiminnot backoff-logiikkaan, jotta voit käsitellä hetkelliset virheet hallitusti.

import asyncio

async def retry(coro_fn, retries=3, base=1):
    for attempt in range(retries):
        try:
            return await coro_fn()
        except Exception as e:
            if attempt == retries - 1: raise
            delay = base * 2 ** attempt
            await asyncio.sleep(delay)

Hallittu alasajo

Ota asyncio.CancelledError kiinni pitkäkestoisissa tehtävissä ja käsittele käyttöjärjestelmän signaalit hallittua alasajoa varten.

import asyncio, signal

async def server():
    stop = asyncio.Event()
    loop = asyncio.get_running_loop()
    loop.add_signal_handler(signal.SIGINT, stop.set)
    await stop.wait()
    print("Shutting down gracefully")

Vastausten suoratoisto

Käytä asynkronisia generaattoreita suurten vastausten suoratoistoon ilman, että koko vastaus ladataan muistiin kerralla.

import asyncio, aiohttp

async def stream(url):
    async with aiohttp.ClientSession() as s:
        async with s.get(url) as r:
            async for chunk in r.content.iter_chunked(4096):
                process(chunk)

async def process(chunk):
    await asyncio.sleep(0)
    print(len(chunk), "bytes")

Taustatehtävät FastAPIssa

FastAPI:n BackgroundTasks asettaa työt jonoon suoritettaviksi vastauksen lähettämisen jälkeen, joten päätepisteet pysyvät nopeina.

from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

def send_email(to: str, body: str):
    # heavy synchronous work
    pass

@app.post("/register")
async def register(email: str, bg: BackgroundTasks):
    bg.add_task(send_email, email, "Welcome!")
    return {"status": "registered"}

Heartbeat-malli

Suorita säännöllisesti toistuva taustatehtävä pääpalvelinsilmukan rinnalla käyttämällä create_task-toimintoa.

import asyncio

async def heartbeat():
    while True:
        print("alive")
        await asyncio.sleep(30)

async def main():
    asyncio.create_task(heartbeat())
    await serve_forever()

Asynkronisen koodin profilointi

Käytä yappi- tai py-spy-työkalua asynkronisen koodin huomioivaan profilointiin. Ota asyncio-vianmääritystila käyttöön, jotta saat ilmoituksia hitaista takaisinsoitoista.

# Enable debug to catch slow callbacks:
# asyncio.run(main(), debug=True)

# PYTHONASYNCIODEBUG=1 python server.py
# logs: Executing <Task coroutine=...> took 0.150 seconds

Yleisten sudenkuoppien välttäminen

Tärkeimmät säännöt: älä koskaan kutsu estävää koodia tapahtumasilmukassa, odota korutiineja aina, peruuta tehtävät alasajon yhteydessä, käytä yhteyspoolia ja rajoita samanaikaisuutta semaforeilla.

import asyncio

async def bad():
    import time
    time.sleep(2)        # blocks the entire event loop!

async def good():
    await asyncio.sleep(2)  # yields control

Pikatarkistus

Mikä asyncio-primitiivi irrottaa samanaikaisina tehtävinä suoritettavat tuottajat ja kuluttajat toisistaan?

Kertaus

Tuotantokäytön asynkronisia malleja ovat yhteyspoolien käyttö, samanaikaisuuden hallinta Semaphorella, uudelleenyritysten ja backoffin toteuttaminen, suurten tietomäärien suoratoisto, hallittu alasajo signaalien yhteydessä sekä säännöllisten tehtävien suorittaminen komennolla create_task.

Aloita maksutta

Opi Python tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
76
Oppitunnit
320

Usein kysytyt kysymykset

Onko oppitunti ”Asynkronisen I/O:n mallit tuotannossa” ilmainen?

Kyllä – oppitunnin ”Asynkronisen I/O:n mallit tuotannossa” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Python Academy-kurssin, päivitä CoddyKit PROhon. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Asynkronisen I/O:n mallit tuotannossa”?

Soveltakaa asyncioa HTTP-asiakkaisiin, jonoihin ja tosielämän käsittelyputkiin. Harjoittelet Python Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Python Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Python Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Asynkronisen I/O:n mallit tuotannossa”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Python Academy-oppitunnilla?

Kyllä. Jokainen Python Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Korusutiinit ja tapahtumasilmukka
  2. await, tehtävät ja kokoaminen
  3. Asynkroniset kontekstinhallitsijat ja iteraattorit
  4. Asynkronisen I/O:n mallit tuotannossa
← Takaisin: Python Academy