Belajar Python - Concurrency & Parallelism
Episode 15 of 23

Belajar Python - Concurrency & Parallelism

Episode ini membedah threading, multiprocessing, dan asyncio beserta model serta jebakan masing-masing. Kalian juga belajar pola async modern dengan asyncio TaskGroups di Python 3.11 serta alternatif seperti trio dan anyio.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Aplikasi yang menangani banyak hal sekaligus adalah kebutuhan nyata. Episode 15 membedah tiga pendekatan concurrency Python: threading, multiprocessing, dan asyncio. Masing-masing punya model, kekuatan, dan jebakan sendiri.

Kita juga mempelajari pola async modern dengan asyncio.TaskGroup di Python 3.11 serta alternatif seperti trio dan anyio. Dengan pemahaman ini, kalian bisa memilih pendekatan yang tepat untuk setiap masalah.

Memahami I/O-bound vs CPU-bound

Kunci Memilih Pendekatan

Sebelum memilih alat concurrency, kenali jenis beban kerja:

PythonMembedakan beban kerja
import time
 
def io_bound():
    time.sleep(1)
 
def cpu_bound():
    total = 0
    for i in range(10_000_000):
        total += i
    return total

time.sleep(1) meniru beban I/O — menunggu jaringan atau disk. Loop besar meniru beban CPU. I/O-bound cocok dengan threading dan asyncio; CPU-bound cocok dengan multiprocessing. Kesalahan memilih pendekatan membuat aplikasi tidak kencang meski sudah concurrency.

Threading

Model dan Batasan

Threading berjalan dalam satu proses dan berbagi memory, tapi dibatasi GIL untuk kode CPU:

PythonThreading untuk I/O-bound
import threading
import time
 
def kerja(nama):
    time.sleep(1)
    print(f"{nama} selesai")
 
mulai = time.perf_counter()
t1 = threading.Thread(target=kerja, args=("A",))
t2 = threading.Thread(target=kerja, args=("B",))
t1.start()
t2.start()
t1.join()
t2.join()
print(time.perf_counter() - mulai)

threading.Thread(target=kerja, args=("A",)) membuat thread baru. Karena time.sleep melepas GIL, dua thread menyelesaikan tugas bersamaan — total waktu jauh di bawah 2 detik. Untuk I/O-bound, threading efektif.

Multiprocessing

Melewati GIL

Multiprocessing memakai proses terpisah, masing-masing punya interpreter sendiri:

PythonMultiprocessing untuk CPU-bound
from multiprocessing import Pool
 
def hitung(n):
    total = 0
    for i in range(n):
        total += i
    return total
 
if __name__ == "__main__":
    with Pool(4) as pool:
        hasil = pool.map(hitung, [10_000_000] * 4)
    print(hasil)

with Pool(4) as pool: membuat empat proses. pool.map membagi tugas. Berbeda dari thread, proses punya GIL sendiri sehingga komputasi CPU berjalan paralel. Perhatikan guard if __name__ == "__main__" yang wajib untuk multiprocessing di banyak sistem.

asyncio

Event Loop dan Coroutine

asyncio menjalankan banyak tugas dalam satu thread memakai event loop:

Pythonasyncio dasar
import asyncio
 
async def kerja(nama):
    await asyncio.sleep(1)
    return f"{nama} selesai"
 
async def utama():
    hasil = await asyncio.gather(
        kerja("A"),
        kerja("B"),
        kerja("C"),
    )
    print(hasil)
 
asyncio.run(utama())

async def kerja(nama) mendefinisikan coroutine dan await asyncio.sleep(1) menunda tanpa memblokir. asyncio.gather menjalankan banyak coroutine bersamaan. asyncio.run(utama()) memulai event loop. Model ini sangat efisien untuk ribuan koneksi bersamaan.

TaskGroups di Python 3.11

Manajemen Tugas yang Lebih Baik

Python 3.11 memperkenalkan asyncio.TaskGroup untuk mengelola sekelompok tugas secara terstruktur:

PythonMenggunakan TaskGroup
import asyncio
 
async def kerja(nama):
    await asyncio.sleep(1)
    return f"{nama} selesai"
 
async def utama():
    async with asyncio.TaskGroup() as grup:
        tugas = [grup.create_task(kerja(nama)) for nama in ["A", "B", "C"]]
    for t in tugas:
        print(t.result())
 
asyncio.run(utama())

async with asyncio.TaskGroup() as grup: membuat grup tugas. grup.create_task(...) menambahkan tugas yang dijalankan bersamaan. Blok async with menunggu semua selesai, dan membatalkan semua jika ada satu yang gagal — manajemen error yang jauh lebih baik daripada gather.

Alternatif: trio dan anyio

anyio untuk Portabilitas

anyio menyediakan satu API yang berjalan di atas asyncio maupun trio:

Install anyio
pip install anyio
Pythonanyio bekerja di dua backend
import anyio
 
async def kerja(nama):
    await anyio.sleep(1)
    print(f"{nama} selesai")
 
async def utama():
    async with anyio.create_task_group() as grup:
        grup.start_soon(kerja, "A")
        grup.start_soon(kerja, "B")
 
anyio.run(utama)

anyio.create_task_group() membuat task group yang bisa dijalankan di backend mana pun. FastAPI dan Starlette memakai anyio, sehingga kalian bisa memilih backend tanpa mengubah API. Ini investasi portabilitas yang baik.

Penutup

Inti yang harus dibawa pulang:

  • Threading efektif untuk I/O-bound karena GIL dilepas saat menunggu.
  • Multiprocessing memakai proses terpisah untuk melewati GIL.
  • asyncio menjalankan banyak coroutine dalam satu thread.
  • TaskGroup di Python 3.11 mengelola grup tugas dengan pembatalan aman.
  • anyio menyediakan satu API yang berjalan di atas asyncio maupun trio.
  • Pilih pendekatan berdasarkan jenis beban: I/O-bound atau CPU-bound.

Di episode 16 selanjutnya kita akan membahas performance tuning dan profiling — profiler seperti cProfile dan pyinstrument, sampling profiler dan flame graph, optimasi hot path, ekstensi native dengan Cython, serta kapan memakai PyPy. Aplikasi kalian akan berjalan jauh lebih cepat!

Belajar Python - Concurrency & Parallelism | Belajar Python