Materi Tutorial

Multithreading & Multiprocessing Python

Dalam komputasi modern, kita sering mendengar istilah parallelism dan concurrency. Di Python, ada dua cara utama untuk melakukan banyak hal "sekaligus": Multithreading dan Multiprocessing.

Pemilihan antara keduanya sangat bergantung pada jenis tugas yang Anda kerjakan: apakah I/O Bound atau CPU Bound.

1. I/O Bound vs CPU Bound

2. Multithreading (Untuk I/O Bound)

Threading menggunakan thread di dalam satu proses yang sama. Thread berbagi memori yang sama.

Namun, Python (CPython) memiliki GIL (Global Interpreter Lock), yang mencegah dua thread Python mengeksekusi bytecode secara bersamaan di satu core CPU. Jadi, Multithreading di Python tidak membuat kode CPU-bound lebih cepat (malah bisa lebih lambat karena overhead).

Tapi, Multithreading sangat cepat untuk I/O Bound karena saat satu thread menunggu (misal nunggu respons web), thread lain bisa berjalan.

import threading
import time

def unduh_halaman(url):
    print(f"Mulai mengunduh {url}...")
    time.sleep(2) # Simulasi delay jaringan
    print(f"Selesai mengunduh {url}")

start = time.time()

threads = []
urls = ["web1", "web2", "web3"]

for url in urls:
    t = threading.Thread(target=unduh_halaman, args=(url,))
    threads.append(t)
    t.start()

# Tunggu semua thread selesai
for t in threads:
    t.join()

end = time.time()
print(f"Total waktu: {end - start:.2f} detik")
# Output sekitar 2 detik, bukan 6 detik!

3. Multiprocessing (Untuk CPU Bound)

Multiprocessing membuat proses Python baru yang terpisah. Setiap proses memiliki Python interpreter dan ruang memorinya sendiri. Ini membypasses GIL, sehingga bisa menggunakan multi-core CPU secara maksimal.

Gunakan ini untuk tugas komputasi berat.

import multiprocessing
import time

def hitung_kuadrat_berat(angka):
    print(f"Proses {angka} mulai...")
    hasil = sum(i * i for i in range(10**7)) # Perhitungan berat
    print(f"Proses {angka} selesai.")
    return hasil

if __name__ == "__main__":
    start = time.time()
    
    # Membuat 2 proses berjalan paralel di core CPU berbeda
    p1 = multiprocessing.Process(target=hitung_kuadrat_berat, args=(1,))
    p2 = multiprocessing.Process(target=hitung_kuadrat_berat, args=(2,))
    
    p1.start()
    p2.start()
    
    p1.join()
    p2.join()
    
    end = time.time()
    print(f"Total waktu: {end - start:.2f} detik")

Catatan: Anda harus melindungi kode utama dengan if __name__ == "__main__": saat menggunakan multiprocessing di Windows.

4. Concurrent Futures (Cara Modern)

Python menyediakan modul concurrent.futures yang memberikan interface lebih tinggi dan mudah untuk Threading dan Multiprocessing.

from concurrent.futures import ThreadPoolExecutor
import time

def tugas(n):
    time.sleep(1)
    return f"Tugas {n} selesai"

start = time.time()

with ThreadPoolExecutor(max_workers=3) as executor:
    results = executor.map(tugas, [1, 2, 3])
    
    for result in results:
        print(result)

print(f"Waktu: {time.time() - start:.2f} detik")

Ganti ThreadPoolExecutor dengan ProcessPoolExecutor jika ingin beralih ke multiprocessing.

Kesimpulan

Fitur Multithreading Multiprocessing
Memori Berbagi memori (Shared) Memori terpisah (Isolated)
Overhead Rendah Tinggi (butuh waktu start)
Cocok untuk I/O Bound (Network, File) CPU Bound (Math, Data Processing)
GIL Terkena dampak GIL Bebas dari GIL

Edit tutorial ini