CodeShot

Threading در مقابل Multiprocessing

در پایتون، Threading چندین نخ را در یک پردازه اجرا می‌کند اما به دلیل GIL (Global Interpreter Lock) تنها یک نخ در هر لحظه بایت‌کد پایتون اجرا می‌کند؛ Multiprocessing با ایجاد پردازه‌های مستقل، هرکدام با مفسر و حافظه جداگانه، امکان اجرای واقعی موازی روی چند هسته CPU را فراهم می‌کند.

ویژگیThreadingMultiprocessing
مدل اجراچند نخ در یک پردازه (حافظه مشترک)چند پردازه مستقل (حافظه جدا)
تاثیر GILمحدود به یک نخ در هر لحظههر پردازه GIL مستقل خودش را دارد
سربار ایجادکم (سبک‌وزن)زیاد (کپی مفسر و حافظه)
مناسب برایعملیات I/O-boundعملیات CPU-bound

کِی از Threading استفاده کنیم؟

وقتی کار شما I/O-bound است (درخواست شبکه، خواندن فایل، پرس‌وجوی دیتابیس) از Threading استفاده کنید؛ چون در زمان انتظار برای I/O، GIL آزاد می‌شود و نخ‌های دیگر می‌توانند اجرا شوند. سربار حافظه و ایجاد آن نیز بسیار کمتر از Multiprocessing است.

کِی از Multiprocessing استفاده کنیم؟

وقتی کار شما CPU-bound است (محاسبات سنگین، پردازش تصویر، عملیات ریاضی) از Multiprocessing استفاده کنید؛ چون هر پردازه GIL مجزای خودش را دارد و می‌تواند واقعاً روی هسته‌های مختلف CPU به‌صورت موازی اجرا شود.

مثال Threading

import threading, requests

def fetch(url):
    requests.get(url)

threads = [threading.Thread(target=fetch, args=(u,)) for u in urls]
[t.start() for t in threads]
[t.join() for t in threads]

مثال Multiprocessing

from multiprocessing import Pool

def square(n):
    return n * n

with Pool(processes=4) as pool:
    results = pool.map(square, range(1000000))

اشتباه رایج

بسیاری از توسعه‌دهندگان برای تسریع محاسبات سنگین CPU-bound از Threading استفاده می‌کنند و انتظار بهبود کارایی دارند، در حالی که به دلیل GIL هیچ افزایش سرعتی حاصل نمی‌شود (و گاهی به دلیل سربار جابه‌جایی نخ‌ها حتی کندتر هم می‌شود). راه‌حل درست استفاده از Multiprocessing یا کتابخانه‌هایی مثل NumPy است که GIL را در سطح C آزاد می‌کنند.

جمع‌بندی

قانون سریع: I/O-bound → Threading (یا asyncio)، CPU-bound → Multiprocessing.