Soal 1Diberikan async def hello(): return 'Hi', apa yang dikembalikan hello()?
Dasar async / await — Mempercepat Program dengan Memanfaatkan Waktu Tunggu
Pelajari mekanisme coroutine, event loop, dan asyncio.sleep, lalu cara async def / await mengalihkan waktu tunggu I/O ke task lain dan mempercepat program.
async / await adalah mekanisme untuk mengerjakan pekerjaan lain selagi menunggu I/O (Input/Output — pembacaan file, panggilan jaringan, query DB, dan operasi yang didominasi oleh waktu tunggu lainnya). Mekanisme ini bisa mempercepat tugas seperti memanggil Web API 100 kali, tanpa keluar dari satu thread. Artikel ini membahas tiga ide inti: coroutine, event loop, dan asyncio.sleep.
Tentang menjalankan kode di sini
async / await berfokus pada timing, tetapi runner di situs ini menyangga output print dan menampilkannya sekaligus setelah skrip selesai. Output real-time dan rasa waktu yang berlalu tidak akan sama dengan environment Python asli. Artikel ini menggunakan diagram untuk memperjelas perilaku internalnya, tetapi jika kamu ingin melihat aliran print secara langsung atau merasakan timing yang sebenarnya, jalankan di environment Python lokalmu dengan asyncio.run.
Process dan Thread — konteks untuk async / await
Sebelum masuk ke async / await, mari kita pastikan dulu apa itu process dan thread.
Process (satu program yang berjalan dari sudut pandang OS) adalah unit eksekusi independen dengan memory space sendiri. Jalankan satu skrip Python dan kamu mendapatkan satu process; jalankan satu lagi di terminal berbeda dan kamu memiliki dua.
Thread (alur yang sebenarnya menjalankan kode di dalam process) adalah unit yang memakai CPU untuk memajukan kode. Sebuah process bisa memiliki banyak thread, tetapi program Python biasa berjalan sebagai 1 process + 1 thread, dan menunggu seperti time.sleep menghentikan thread tersebut.
- Unit eksekusi independen dari sudut pandang OS
- Memiliki memory space sendiri
- Unit yang benar-benar menjalankan kode di dalam process
- Python biasa umumnya hanya memiliki satu thread yang berjalan
- Bergantian giliran di dalam satu thread
- Kamu bisa membuat sebanyak yang kamu mau dengan
async / await
threading (menambah thread) dan multiprocessing (menambah process).async / await hanya menangani coroutine paling dalam. Mekanisme ini berpindah antar coroutine pada thread yang sama, tanpa pernah menambah thread atau CPU — ia hanya menyerahkan kontrol ke coroutine lain saat CPU menganggur menunggu I/O. Untuk benar-benar menjalankan thread secara paralel, gunakan threading; untuk menambah process, gunakan multiprocessing (dibahas di dua artikel berikutnya).
Apa itu coroutine — bintang dari async / await
Coroutine (fungsi / objek yang didefinisikan dengan async def yang bisa berhenti sementara di titik await internal) adalah inti dari async / await. Fungsi biasa berjalan lurus sampai akhir saat dipanggil, tetapi coroutine bisa berhenti sementara di setiap await internal dan melanjutkan ketika event loop menyuruhnya. Itulah fondasi yang menjadi dasar async.
Memanggil fungsi async def tidak menjalankan body-nya — ia hanya mengembalikan objek coroutine (misalnya, coro = hello()). Body baru mulai berjalan saat kamu await coro atau meneruskannya ke asyncio.run(coro).
import asyncio
async def hello():
return "Hi"
# Memanggilnya tidak menjalankan body
coro = hello()
print(coro) # <coroutine object hello at 0x...>
# ↑ 0x... adalah alamat memori.
# Itu hanya berarti "sebuah coroutine telah dibuat"
# await yang sebenarnya menjalankannya
print(await coro) # Hi
return mengakhirinya. Titik await internal berhenti sementara dan melanjutkan di antaranya.Saat kamu menulis await some_io(), coroutine berhenti sementara dan beralih ke task lain, dan coroutine lain bisa berjalan selagi coroutine ini menunggu — itulah fitur khas async.
Apa itu event loop — scheduler yang menggilir coroutine
Event loop (scheduler yang menggilir coroutine bergantian) adalah yang dijalankan asyncio di balik layar. Ia berputar tanpa henti: ambil coroutine dari antrean → jalankan → beralih ke yang lain di await → kembalikan yang penantiannya selesai ke antrean.
import asyncio
async def main():
print("start")
await asyncio.sleep(0) # sleep(0) tidak benar-benar menunggu,
# ia hanya menandai "boleh beralih di sini"
print("end")
# asyncio.run memulai loop → menjalankan main → menutup loop saat selesai
asyncio.run(main())
# Output:
# start
# end
Semua ini terjadi di satu thread — tanpa core CPU tambahan, hanya mengisi waktu tunggu yang menganggur dengan coroutine lain. Di Python berbasis browser di situs ini, event loop sudah berjalan, sehingga kamu bisa menulis await langsung di top level tanpa memanggil asyncio.run(...).
Kenapa async / await — beralih ke task lain saat menunggu
Di kode sinkron (sync) (gaya baris demi baris yang biasa), time.sleep(1) memblokir program — CPU menganggur, tetapi program membeku. Hal yang sama berlaku untuk respons Web API, query DB, dan penyelesaian I/O file.
async / await memungkinkan kamu beralih ke task lain di mana pun kamu menulis "tunggu", tetap di thread yang sama tetapi beralih saat penantian dimulai.
# requests = HTTP client sinkron (satu panggilan dalam satu waktu)
# httpx = HTTP client yang mendukung async (await panggilan secara paralel)
import requests, asyncio, httpx
# Sync: panggil 3 API satu per satu → total 3 detik
def fetch_users_sync():
r1 = requests.get("https://api.example.com/users/1") # ← menunggu 1 detik
r2 = requests.get("https://api.example.com/users/2") # ← 1 detik lagi
r3 = requests.get("https://api.example.com/users/3") # ← 1 detik lagi
return [r1.json(), r2.json(), r3.json()]
# Async: panggil 3-nya secara paralel → selesai dalam ~1 detik (yang paling lambat)
async def fetch_users_async():
async with httpx.AsyncClient() as client:
r1, r2, r3 = await asyncio.gather(
client.get("https://api.example.com/users/1"),
client.get("https://api.example.com/users/2"),
client.get("https://api.example.com/users/3"),
)
return [r1.json(), r2.json(), r3.json()]
Detail asyncio.gather menyusul
asyncio.gather(...) yang dipakai di sini menjalankan beberapa coroutine secara konkuren dan menunggu semua hasilnya. Semantik detailnya — nilai kembalian, penanganan exception — dibahas di artikel berikutnya: asyncio Tasks.
Concurrent, bukan parallel
async / await tidak pernah menambah CPU — kode yang memaksimalkan CPU (komputasi berat) tidak akan dipercepat. Ia hanya mengisi waktu CPU yang menganggur saat "menunggu I/O / menunggu jaringan / sleep" dengan beralih ke task lain. Ini eksekusi concurrent, bukan eksekusi parallel sejati. Untuk benar-benar berjalan di banyak core, kamu perlu threading atau multiprocessing — dibahas di dua artikel berikutnya.
async def dan await — dasarnya
Fungsi yang didefinisikan dengan async def disebut fungsi coroutine — memanggilnya tidak menjalankan body, hanya mengembalikan objek coroutine. Untuk benar-benar menjalankannya, await ia atau teruskan ke asyncio.run().
await x berarti "tunggu x selesai, sambil beralih ke task lain di sela-sela". x bisa salah satu dari tiga hal: coroutine (fokus artikel ini), Task, atau Future (objek Task yang dibahas di artikel berikutnya, plus objek pemberitahuan penyelesaian yang dipakainya secara internal) — dalam kode sehari-hari, kamu kebanyakan akan memakai coroutine atau Task.
import asyncio
# Definisikan fungsi coroutine dengan async def
async def hello():
return "Hi"
# Memanggilnya hanya mengembalikan objek coroutine (body tidak berjalan)
print(hello()) # <coroutine object hello at 0x...>
# await menjalankannya (top-level await bekerja di environment browser ini)
result = await hello()
print(result) # Hi
# Di skrip Python asli, bungkus dengan asyncio.run()
# print(asyncio.run(hello())) # Hi
| Elemen | Arti | Catatan |
|---|---|---|
| async def f(): | Mendefinisikan fungsi coroutine | Memanggilnya tidak menjalankan body |
| f() | Membuat objek coroutine | Butuh await untuk benar-benar berjalan |
| await f() | Menunggu penyelesaian, sambil beralih ke yang lain | Hanya legal di dalam fungsi async |
| asyncio.sleep(N) | Tunggu N detik (memberikan giliran selama menunggu) | Tidak memblokir seperti time.sleep |
| asyncio.run(f()) | Berjalan dari top level | Entry point standar di Python asli |
Tanpa await, coroutine tidak akan pernah berjalan
Jika kamu menulis hello() saja, body tidak akan pernah berjalan, dan kamu akan melihat peringatan seperti <coroutine object hello at 0x...> di console. Selalu await hello() atau jalankan via asyncio.run(hello()). "Memanggil" dan "menjalankan" adalah dua hal berbeda di async — bedakan keduanya.
Eksekusi konkuren membagi penantian — keuntungan asyncio
asyncio.sleep(seconds) adalah versi async dari sleep — ia beralih ke task lain selama menunggu. Dikombinasikan dengan asyncio.gather (artikel berikutnya) untuk menjalankan beberapa coroutine sekaligus, semua sleep berjalan secara konkuren, sehingga total waktunya menjadi sleep tunggal terlama (bukan jumlahnya, seperti yang akan diberikan time.sleep).
Secara internal, asyncio.sleep(N) mendaftarkan "lanjutkan coroutine ini dalam N detik" ke loop dan langsung beralih keluar. Sebaliknya, time.sleep(N) adalah panggilan OS yang sepenuhnya memblokir CPU — loop juga berhenti, dan tidak ada coroutine lain yang bisa berjalan. Memakai time.sleep di dalam fungsi async menggagalkan tujuan utama async, jadi hati-hati.
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Di dalam fungsi async, mana yang "menunggu N detik sambil beralih ke task lain"?
Soal 3Workload mana yang paling diuntungkan oleh async / await?