Multithreading & Multiprocessing

Speed up Python programs with concurrency

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

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