Multiprocessing vs Multithreading di Python: Panduan Lengkap
Concurrency dan parallelism adalah konsep penting dalam programming modern untuk meningkatkan performa aplikasi. Python menyediakan dua pendekatan utama: multithreading dan multiprocessing. Dalam tutorial ini, kita akan mempelajari perbedaan keduanya, kapan menggunakan masing-masing, dan bagaimana mengimplementasikannya dengan efektif.
Konsep Dasar
Threading
Thread adalah unit eksekusi terkecil dalam sebuah process. Multiple threads dalam satu process berbagi memory space yang sama. Karakteristik Threading:- Lightweight (ringan)
- Berbagi memory space
- Context switching lebih cepat
- Cocok untuk I/O-bound tasks
Multiprocessing
Process adalah instance independen dari program yang berjalan. Setiap process memiliki memory space sendiri. Karakteristik Multiprocessing:- Heavyweight (lebih berat)
- Memory space terpisah
- True parallelism
- Cocok untuk CPU-bound tasks
Global Interpreter Lock (GIL)
Apa itu GIL?
GIL adalah mutex (mutual exclusion lock) yang melindungi akses ke Python objects, mencegah multiple threads mengeksekusi Python bytecode secara bersamaan.
Implikasi GIL:import threading
import time
CPU-bound task
def cpuintensive():
count = 0
for i in range(50000000):
count += 1
return count
Single thread
start = time.time()
cpuintensive()
cpuintensive()
end = time.time()
print(f"Single thread: {end - start:.2f}s")
Multi-threading (TIDAK lebih cepat karena GIL!)
start = time.time()
t1 = threading.Thread(target=cpuintensive)
t2 = threading.Thread(target=cpuintensive)
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()
print(f"Multi-threading: {end - start:.2f}s")
Output:
Single thread: 3.45s
Multi-threading: 3.52s # Tidak ada speedup!
Kesimpulan: Threading di Python TIDAK memberikan speedup untuk CPU-bound tasks karena GIL.
Kapan Menggunakan Threading
Threading efektif untuk I/O-bound tasks karena GIL dilepas saat waiting for I/O.
Contoh 1: Download Multiple Files
import threading
import requests
import time
urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3',
'https://jsonplaceholder.typicode.com/posts/4',
'https://jsonplaceholder.typicode.com/posts/5',
]
def download(url):
"""Download content dari URL"""
response = requests.get(url)
print(f"Downloaded {url}: {len(response.content)} bytes")
Sequential (tanpa threading)
start = time.time()
for url in urls:
download(url)
sequentialtime = time.time() - start
print(f"\nSequential: {sequentialtime:.2f}s")
Multi-threading
start = time.time()
threads = []
for url in urls:
thread = threading.Thread(target=download, args=(url,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
threadedtime = time.time() - start
print(f"Multi-threading: {threadedtime:.2f}s")
print(f"Speedup: {sequentialtime/threadedtime:.2f}x")
Output:
Downloaded https://jsonplaceholder.typicode.com/posts/1: 292 bytes
Downloaded https://jsonplaceholder.typicode.com/posts/2: 293 bytes
...
Sequential: 2.45s
Multi-threading: 0.62s
Speedup: 3.95x # Significant speedup!
Contoh 2: Database Queries
import threading
import sqlite3
import time
def querydatabase(query, resultlist, index):
"""Execute database query"""
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute(query)
result = cursor.fetchall()
resultlist[index] = result
conn.close()
print(f"Query {index+1} completed: {len(result)} rows")
Multiple queries
queries = [
"SELECT FROM users WHERE age > 25",