asyncio — Asynchronous I/O
Peta modul asyncio: bagian mana yang untuk penulis aplikasi, dan bagian mana yang untuk penulis library.
Intisari
- Dokumentasi asyncio dibagi dua: API tingkat tinggi (untukmu) dan API tingkat rendah (untuk penulis library).
- Sebagai penulis aplikasi, kamu hanya butuh bagian Runners, Coroutines and Tasks, dan Synchronization Primitives.
Semaphoremembatasi jumlah operasi bersamaan — wajib untuk API berbayar.Queuemenghubungkan producer dan consumer async dengan backpressure otomatis.- Abaikan Transports, Protocols, Event Loop API, Subprocess — tidak relevan untuk kode LLM.
Cara membaca halaman ini
| Bagian | Untuk siapa | Perlu? |
|---|---|---|
| Runners | Penulis aplikasi | ✅ asyncio.run() |
| Coroutines and Tasks | Penulis aplikasi | ✅ Halaman terpenting |
| Streams | Penulis aplikasi | ⚠️ Kalau bikin protokol TCP sendiri |
| Synchronization Primitives | Penulis aplikasi | ✅ Semaphore, Lock, Event |
| Queues | Penulis aplikasi | ✅ Pola producer/consumer |
| Subprocesses | Penulis aplikasi | ⚠️ Jarang |
| Exceptions | Penulis aplikasi | ✅ Baca sekilas |
| Event Loop / Futures / Transports / Protocols / Policies | Penulis library | ❌ Lewati |
Semaphore — yang paling sering kamu pakai
import asyncio
sem = asyncio.Semaphore(5)
async def panggil_llm(prompt: str) -> str:
async with sem: # tunggu giliran kalau 5 slot sudah terpakai
return await client.messages.create(...)
# 500 prompt, tapi maksimal 5 request berjalan pada satu waktu
hasil = await asyncio.gather(*(panggil_llm(p) for p in prompts))
Cara menentukan angkanya: lihat rate limit penyedia API-mu (request per menit), bagi dengan perkiraan durasi tiap request. Kalau limitnya 60 RPM dan tiap panggilan ~10 detik, maka 10 concurrency sudah pas. Mulai dari angka kecil (5), naikkan sambil memantau error 429.
Primitif sinkronisasi lainnya
Lock — akses eksklusif
lock = asyncio.Lock()
async def tambah_ke_index(chunk):
async with lock:
index.append(chunk) # hanya satu task di sini pada satu waktu
Jarang dibutuhkan di async. Coroutine hanya berpindah di titik await,
jadi operasi tanpa await di dalamnya sudah otomatis atomik. Kamu butuh
Lock hanya kalau ada await di tengah operasi yang harus utuh.
Event — sinyal antar task
siap = asyncio.Event()
async def penyiap():
await muat_index()
siap.set() # beri sinyal
async def pekerja():
await siap.wait() # tunggu sinyal
await proses()
Queue — producer / consumer
async def producer(q: asyncio.Queue):
for path in Path("docs").rglob("*.md"):
await q.put(path) # blokir kalau antrean penuh → backpressure
for _ in range(N_WORKER):
await q.put(None) # sinyal berhenti
async def consumer(q: asyncio.Queue):
while True:
path = await q.get()
if path is None:
q.task_done()
break
await proses(path)
q.task_done()
async def main():
q = asyncio.Queue(maxsize=100) # batas ukuran = kendali memori
async with asyncio.TaskGroup() as tg:
tg.create_task(producer(q))
for _ in range(N_WORKER):
tg.create_task(consumer(q))
maxsize memberi backpressure gratis. Kalau consumer lebih lambat dari
producer, q.put() akan menunggu — sehingga producer melambat sendiri alih-alih
memenuhi RAM dengan ribuan item yang belum diproses. Ini pola yang tepat untuk pipeline
ingest RAG di Fase 7.
Exception yang perlu dikenali
| Exception | Kapan muncul |
|---|---|
TimeoutError | asyncio.timeout() atau wait_for() terlampaui |
CancelledError | Task dibatalkan — jangan ditelan |
ExceptionGroup | Beberapa task di TaskGroup gagal sekaligus |
InvalidStateError | Ambil hasil task yang belum selesai |
# ❌ menelan CancelledError merusak mekanisme pembatalan
try:
await sesuatu()
except Exception:
pass
# ✅ bersihkan lalu lempar ulang
try:
await sesuatu()
except asyncio.CancelledError:
await bersihkan()
raise
Ekosistem sekitarnya
| Library | Untuk |
|---|---|
httpx | HTTP client async — dipakai di roadmap ini |
anyio | Abstraksi di atas asyncio; dipakai internal oleh FastAPI |
aiofiles | Operasi file async (jarang perlu — to_thread biasanya cukup) |
asyncpg / aiosqlite | Driver database async |
uvloop | Event loop alternatif yang lebih cepat |
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.