The Process Class
multiprocessing.Process spawns a new OS process.
Python
from multiprocessing import Process
import os
def worker(name):
print(f"Worker {name} | PID: {os.getpid()}")
if __name__ == "__main__": # Required on Windows!
processes = []
for i in range(3):
p = Process(target=worker, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()βΆ Output
Worker 0 | PID: 12345
Worker 1 | PID: 12346
Worker 2 | PID: 12347Tip
Always put multiprocessing code inside if __name__ == "__main__": to prevent recursive spawning on Windows.
Pool β Parallel Map Operations
Pool distributes work across multiple CPU cores automatically.
Python
from multiprocessing import Pool
import time
def square(n):
time.sleep(0.1) # Simulate work
return n * n
if __name__ == "__main__":
numbers = list(range(8))
# Sequential: 0.8s
# With 4 workers: ~0.2s
with Pool(processes=4) as pool:
results = pool.map(square, numbers)
print(results)βΆ Output
[0, 1, 4, 9, 16, 25, 36, 49]ProcessPoolExecutor β Modern API
concurrent.futures.ProcessPoolExecutor is the high-level interface for multiprocessing.
Python
from concurrent.futures import ProcessPoolExecutor
def heavy_computation(n):
return sum(i**2 for i in range(n))
if __name__ == "__main__":
inputs = [1_000_000, 2_000_000, 3_000_000]
with ProcessPoolExecutor(max_workers=3) as exe:
results = list(exe.map(heavy_computation, inputs))
print(results)βΆ Output
[333332833333500000, 2666666000000, 9000001500000]Ad β 336Γ280
Multiprocessing vs Threading
Choose the right tool for the job.
Python
# I/O bound (waiting for network, disk, DB)
# β Use threading or asyncio
# β Threads share memory, low overhead
# CPU bound (calculation, image processing)
# β Use multiprocessing
# β Each process gets full CPU core
# β Bypasses the GIL
# Rule of thumb:
import os
CPU_COUNT = os.cpu_count()
print(f"Available cores: {CPU_COUNT}")