Penyebab Perlambatan Kode Async dan Cara Mengatasinya (Ringkasan teknis)
Video ini membahas penyebab umum mengapa kode asyncio Python bisa lebih lambat daripada kode sinkron, serta metodologi teknis untuk mengatasinya.
1. Konsep inti Asyncio
- Event Loop: Inti dari semua aplikasi asinkron. Dimulai dengan
asyncio.run(), lalu mengelola dan menjadwalkan eksekusi task di satu thread. - Coroutine: Fungsi asinkron yang dideklarasikan dengan
async def. Saat menemui kata kunciawait, eksekusi dapat dijeda dan kontrol dikembalikan ke event loop. - Task: Membungkus coroutine dan menjadwalkannya agar berjalan secara bersamaan di event loop. Dibuat melalui
asyncio.create_task(). - Future: Objek level rendah yang merepresentasikan hasil akhir dari pekerjaan asinkron.
2. Contoh konversi kode sinkron ke asinkron
Gantilah time.sleep() sinkron yang ada dengan await asyncio.sleep() yang asinkron, deklarasikan fungsi dengan async def, dan jalankan coroutine utama dengan asyncio.run().
Kesalahan umum yang menyebabkan penurunan performa dan solusinya
Kesalahan 1: Eksekusi berurutan (Sequential Execution)
Jika task-task independen di-await secara berurutan alih-alih dijalankan paralel, total waktu eksekusi akan menjadi penjumlahan waktu semua task.
-
Contoh yang salah (berurutan):
# Setiap await menunggu sampai pekerjaan sebelumnya selesai await get_user_notifications() await get_recent_activity() await get_unread_messages() -
Solusi (paralel): Gunakan
asyncio.gatheratauasyncio.TaskGroupuntuk menjalankan task-task independen secara bersamaan. Total waktu eksekusi dapat turun menjadi sebesar waktu task yang paling lama.# Tiga pekerjaan dimulai pada saat yang sama await asyncio.gather( get_user_notifications(), get_recent_activity(), get_unread_messages() )
Perbandingan alat eksekusi paralel
asyncio.gather:- Menjalankan beberapa coroutine secara bersamaan.
- Kekurangan: penanganan error kurang baik. Jika exception terjadi di satu task, task lain yang sedang berjalan akan dibatalkan.
asyncio.create_task:- Memungkinkan kontrol dan penanganan error per task.
- Berguna untuk eksekusi di background, tetapi merepotkan karena beberapa task harus di-
awaitsatu per satu.
asyncio.TaskGroup(Python 3.11+):- Alternatif modern untuk 'structured concurrency'.
- Mengelola grup task dengan sintaks
async with, dan saat keluar dari konteks dipastikan semua task selesai atau exception telah ditangani.
async with asyncio.TaskGroup() as tg: tg.create_task(some_coro_1()) tg.create_task(some_coro_2()) # Saat blok 'async with' berakhir, semua task telah di-await
Kesalahan 2: Menggunakan library sinkron
Jika library sinkron (blocking) seperti requests atau pathlib digunakan di dalam kode asyncio, seluruh event loop akan terblokir. Bahkan jika dipakai di dalam asyncio.gather, perilakunya tetap pada praktiknya menjadi berurutan.
- Solusi: Gunakan library khusus yang mendukung asinkron (non-blocking) seperti
aiohttp(pengganti requests),aiofiles(pengganti files/pathlib), dan sejenisnya.
Kesalahan 3: Event loop terblokir oleh pekerjaan CPU-bound
Karena asyncio berjalan di satu thread, pekerjaan komputasi berat (CPU-bound) akan menghentikan event loop dan menunda pekerjaan I/O lainnya.
- Solusi: Gunakan
loop.run_in_executor()untuk memindahkan pekerjaan CPU-bound ke thread pool terpisah (default) atau process pool.loop = asyncio.get_running_loop() # Menjalankan fungsi yang intensif CPU di thread terpisah await loop.run_in_executor( None, # gunakan thread pool default cpu_bound_function, arg1 )
Kesalahan 4: Pemblokiran akibat pekerjaan yang tidak penting
Jika pekerjaan non-inti seperti logging yang tidak terkait dengan respons pengguna tetap di-await, waktu respons akan tertunda secara tidak perlu.
- Solusi: Gunakan
asyncio.create_task()untuk memisahkan pekerjaan tersebut sebagai background task dan jangan di-await.user_profile = await get_user_profile() # Jalankan logging di background tanpa await asyncio.create_task(send_logs_to_external_service()) return user_profile
Kesalahan 5: Membuat terlalu banyak task
Jika pekerjaan yang sangat kecil dijadikan task dalam jumlah besar, overhead context switching bisa muncul dan menurunkan performa.
- Solusi 1: Gabungkan pekerjaan kecil (batching) menjadi beberapa task yang lebih besar.
- Solusi 2: Gunakan
asyncio.Semaphoreuntuk membatasi jumlah maksimum task yang berjalan bersamaan.# Izinkan maksimal 10 pekerjaan berjalan bersamaan semaphore = asyncio.Semaphore(10) async with semaphore: await fetch_data()
Kesalahan lainnya
- Coroutine "Never Awaited": Coroutine dipanggil tetapi tidak di-
await, sehingga pekerjaannya bahkan tidak dijalankan dan gagal secara diam-diam. Ini dapat dideteksi dengan linter sepertiflake8-async. - Manajemen resource yang tidak tepat: Jika file, koneksi DB, dan sejenisnya digunakan tanpa
try...finally, kebocoran resource bisa terjadi. Solusinya adalah memakai asynchronous context manager denganasync with.
Debugging dan pemilihan model konkurensi
Mode debug Asyncio
Jika mode debug yang secara default nonaktif diaktifkan (asyncio.run(debug=True)), hal ini membantu mendeteksi masalah seperti berikut.
- Coroutine yang tidak di-
await(RuntimeWarning). - API asinkron yang dipanggil dari thread yang salah.
- Callback dengan waktu eksekusi melebihi 100ms.
- Operasi selector I/O yang lambat.
Alat debugging lainnya
- Scalene: Profiler CPU dan memori.
- aio-monitor: Monitoring dan CLI untuk aplikasi
asyncio. - pdb: Debugger bawaan Python.
- py-stack: Menampilkan stack trace proses Python yang sedang berjalan untuk mendeteksi titik pemblokiran.
Panduan memilih model konkurensi
- Asyncio (single-thread): Paling cocok untuk banyak pekerjaan I/O-bound dengan latensi tinggi, misalnya request jaringan atau file I/O.
- Threads (multi-thread): Digunakan untuk pekerjaan I/O-bound yang membutuhkan akses ke data bersama. Karena GIL (Global Interpreter Lock), ini bukan paralelisme sejati, tetapi thread lain bisa berjalan saat menunggu I/O.
- Processes (multi-process): Digunakan untuk pekerjaan CPU-bound seperti pemrosesan gambar atau komputasi berat. Dapat memanfaatkan banyak inti CPU untuk mencapai paralelisme sejati, tetapi overhead memori dan komunikasi lebih besar.
Belum ada komentar.