Python

Panduan Belajar Python: Concurrency & Parallelism

Language

Panduan ini untuk siapa

  • Pembelajar yang membangun program untuk menangani banyak tugas sekaligus
  • Developer yang menentukan pilihan antara threads, processes, dan pendekatan async
  • Engineer yang mengoptimalkan beban kerja I/O-heavy atau CPU-heavy

Apa yang akan Anda pelajari

  • Perbedaan concurrency dan parallelism
  • Bagaimana GIL memengaruhi threading di CPython
  • Kapan menggunakan threading, multiprocessing, dan asyncio
  • Cara kerja async/await dan event loop dalam praktik
  • Panduan pemilihan praktis untuk workload nyata

Mengapa topik ini penting

Aplikasi modern sering melakukan banyak operasi sekaligus: network call, file I/O, background job, dan user request. Memilih model eksekusi yang salah bisa membuang resource atau membuat kode jadi tidak perlu rumit.

Python menyediakan beberapa opsi concurrency, masing-masing punya kelebihan dan trade-off. Memahami kapan memakai tiap pendekatan membantu Anda membangun sistem yang responsif dan efisien.

Konsep inti

Concurrency vs parallelism dan GIL

Concurrency berarti mengelola banyak tugas sepanjang waktu. Parallelism berarti tugas dieksekusi pada saat yang sama di banyak core.

Di CPython, Global Interpreter Lock (GIL) hanya mengizinkan satu thread mengeksekusi Python bytecode pada satu waktu. Ini terutama penting untuk tugas CPU-bound.

Aturan praktis:

  • Tugas I/O-bound -> threads atau asyncio
  • Tugas CPU-bound -> multiprocessing

Threading dan multiprocessing

Threading cocok untuk tugas menunggu (network, disk, API).

import threading
import time


def task(name):
	time.sleep(1)
	print(f"Done: {name}")


threads = [threading.Thread(target=task, args=(f"t{i}",)) for i in range(3)]
for thread in threads:
	thread.start()
for thread in threads:
	thread.join()

Multiprocessing menjalankan process terpisah dan bisa memakai banyak CPU core untuk komputasi berat.

Asyncio untuk I/O concurrency tinggi

asyncio berbasis event loop dan unggul saat banyak tugas I/O perlu dikoordinasikan secara efisien.

import asyncio


async def fetch(name, delay):
	await asyncio.sleep(delay)
	return f"{name} done"


async def main():
	results = await asyncio.gather(
		fetch("A", 1),
		fetch("B", 1),
		fetch("C", 1),
	)
	print(results)


asyncio.run(main())

Pendekatan ini menghindari pembuatan banyak thread untuk skenario high I/O concurrency.

Panduan langkah demi langkah

Langkah 1 — Klasifikasikan jenis workload terlebih dahulu

Sebelum menulis concurrency, identifikasi biaya dominan:

  • Menunggu network/file -> I/O-bound
  • Komputasi numerik berat -> CPU-bound

Satu keputusan ini menentukan pilihan tool.

Langkah 2 — Implementasi versi concurrent kecil

Untuk workload mirip I/O wait, bandingkan sequential vs concurrent.

import time
import asyncio


async def io_task():
	await asyncio.sleep(1)


async def run_concurrent():
	await asyncio.gather(*(io_task() for _ in range(5)))


start = time.perf_counter()
asyncio.run(run_concurrent())
print(f"Elapsed: {time.perf_counter() - start:.2f}s")

Anda biasanya akan melihat runtime mendekati satu detik, bukan lima.

Langkah 3 — Tambahkan safety dan observability

Concurrency menambah kompleksitas. Tambahkan:

  • Timeouts
  • Error handling per task
  • Logging/task naming

Reliability sama pentingnya dengan peningkatan kecepatan.

Contoh praktis

Contoh 1 — CPU-bound dengan multiprocessing

from multiprocessing import Pool


def square(n):
	return n * n


if __name__ == "__main__":
	with Pool() as pool:
		print(pool.map(square, [1, 2, 3, 4, 5]))

Expected output:

[1, 4, 9, 16, 25]

Pola ini menskalakan tugas CPU lebih baik daripada thread pada banyak kasus CPython.

Contoh 2 — Penanganan timeout pada task async

import asyncio


async def slow():
	await asyncio.sleep(3)
	return "done"


async def main():
	try:
		result = await asyncio.wait_for(slow(), timeout=1)
		print(result)
	except asyncio.TimeoutError:
		print("Task timed out")


asyncio.run(main())

Expected output:

Task timed out

Contoh 3 — Snapshot perbandingan performa (workload mirip I/O)

import asyncio
import threading
import time


def io_sleep():
	time.sleep(1)


def run_sequential():
	start = time.perf_counter()
	for _ in range(5):
		io_sleep()
	return time.perf_counter() - start


def run_threading():
	start = time.perf_counter()
	threads = [threading.Thread(target=io_sleep) for _ in range(5)]
	for thread in threads:
		thread.start()
	for thread in threads:
		thread.join()
	return time.perf_counter() - start


async def run_asyncio():
	start = time.perf_counter()
	await asyncio.gather(*(asyncio.sleep(1) for _ in range(5)))
	return time.perf_counter() - start


seq_time = run_sequential()
thr_time = run_threading()
async_time = asyncio.run(run_asyncio())

print(f"Sequential: {seq_time:.2f}s")
print(f"Threading : {thr_time:.2f}s")
print(f"Asyncio   : {async_time:.2f}s")

Expected output (typical):

Sequential: ~5.00s
Threading : ~1.00s
Asyncio   : ~1.00s

Perbandingan sederhana ini menunjukkan mengapa strategi concurrency harus sesuai jenis workload.

Kesalahan umum dan cara menghindarinya

  • Memakai thread untuk pekerjaan CPU-heavy di CPython -> Utamakan multiprocessing untuk tugas CPU paralel.
  • Mencampur blocking call di dalam function async -> Gunakan library async-compatible dan hindari operasi blocking di event loop.
  • Menambahkan concurrency sebelum mengukur bottleneck -> Profile dulu, lalu optimasi area yang tepat.
  • Mengabaikan cancellation/timeouts -> Tambahkan jalur timeout dan cancellation demi ketahanan.

Latihan cepat

  • Implementasikan satu tugas I/O secara sequential dan dengan asyncio.gather, lalu bandingkan runtime.
  • Implementasikan function CPU-heavy dan uji dengan multiprocessing pool.
  • Tambahkan timeout handling ke operasi async dan catat event timeout.

Ringkasan utama

  • Pilih model concurrency berdasarkan jenis workload, bukan tren.
  • Threads dan asyncio cocok untuk tugas I/O-bound; multiprocessing cocok untuk tugas CPU-bound.
  • GIL adalah constraint desain penting untuk perilaku thread di CPython.
  • Concurrency membutuhkan error handling dan observability yang kuat agar aman di production.

Langkah berikutnya

Lanjut ke Web Frameworks & Pengembangan Aplikasi. Di panduan berikutnya, Anda akan membandingkan framework Python utama dan memilih yang paling sesuai dengan jenis aplikasi Anda.

No Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.