1. Why Multithreading and Multiprocessing?
Python programs by default sequentially execute hote hain. Agar ek task time consuming ho (jaise I/O, API calls, ya heavy computation), to dusra task uska wait karta hai. Multithreading aur multiprocessing concurrency laate hain, jisse tasks parallel ya concurrent chal sakte hain.
2. Multithreading
Multithreading ek process ke andar multiple threads run karta hai. Ye mainly I/O-bound tasks ke liye useful hai (jaise file download, API calls, DB queries).
import threading
import time
def worker(name):
print(f"Thread {name} starting")
time.sleep(2)
print(f"Thread {name} finished")
# Create threads
t1 = threading.Thread(target=worker, args=("A",))
t2 = threading.Thread(target=worker, args=("B",))
t1.start()
t2.start()
t1.join()
t2.join()
print("All threads completed!")
Output:
Thread A starting
Thread B starting
Thread A finished
Thread B finished
All threads completed!
3. Multiprocessing
Multiprocessing me multiple processes run hote hain, jo alag-alag CPU cores pe execute karte hain. Ye CPU-bound tasks ke liye useful hai (jaise heavy calculations).
import multiprocessing
import time
def square(n):
print(f"Square of {n}: {n*n}")
time.sleep(1)
if __name__ == "__main__":
numbers = [1, 2, 3, 4]
processes = []
for num in numbers:
p = multiprocessing.Process(target=square, args=(num,))
processes.append(p)
p.start()
for p in processes:
p.join()
print("All processes completed!")
4. Threading vs Multiprocessing
- Threading: Best for I/O-bound tasks (file read/write, network requests).
- Multiprocessing: Best for CPU-bound tasks (math-heavy computations, ML training).
- Multiprocessing uses more memory but fully utilizes multiple CPU cores.
5. ThreadPool and ProcessPool Executors
Python me concurrent.futures library easy way deti hai thread pool aur process pool use karne ka.
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def task(n):
return n*n
# Thread Pool
with ThreadPoolExecutor() as executor:
results = executor.map(task, [1, 2, 3, 4])
print(list(results))
# Process Pool
with ProcessPoolExecutor() as executor:
results = executor.map(task, [1, 2, 3, 4])
print(list(results))
Summary
- Threading: Lightweight, shared memory, I/O tasks.
- Multiprocessing: Multiple processes, full CPU utilization, heavy computation.
- Executors: Simplify threading and multiprocessing.