تكرار السؤال: …
الإجابة المختصرة
في CPython التقليدي يسمح الـ GIL لخيط واحد فقط بتنفيذ bytecode في اللحظة نفسها، فلا تستفيد المهام الحسابية (CPU-bound) من threads. ومنذ Python 3.13 يوجد build تجريبي بدون GIL (free-threaded)، وأصبح مدعومًا رسميًا في Python 3.14.
الشرح
الـ threads مفيدة مع I/O لأن انتظار الشبكة أو القرص يحرر الـ GIL، ومكتبات C مثل NumPy تحرره أثناء الحسابات الثقيلة. للأعمال الحسابية في Python النقية استخدم multiprocessing أو ProcessPoolExecutor أو InterpreterPoolExecutor (Python 3.14). نسخة free-threaded (python3.14t) تسمح بتوازٍ حقيقي بين الخيوط، لكنها تأتي ببطء أحادي الخيط بسيط، وتتطلب أن تكون الامتدادات المكتوبة بـ C متوافقة، وتجعل الحاجة إلى locks لحماية الحالة المشتركة أكثر وضوحًا.
مثال بالكود
import sys
from concurrent.futures import ProcessPoolExecutor
print(sys._is_gil_enabled()) # Python 3.13+: False في الـ free-threaded build
def crunch(n: int) -> int:
return sum(i * i for i in range(n))
with ProcessPoolExecutor() as pool: # توازٍ حقيقي مع GIL
results = list(pool.map(crunch, [10**7] * 4))أخطاء شائعة
- استخدام threads لتسريع حسابات Python نقية في CPython التقليدي وتوقع تحسن.
- الاعتقاد بأن الـ GIL يحمي الكود من race conditions؛ فعمليات مثل counter += 1 ليست ذرية.
أسئلة متابعة
- كيف تختار بين multiprocessing و free-threaded Python والـ subinterpreters لتوازي معالجة البيانات؟
- كيف تشغّل دالة حاجبة (blocking) داخل asyncio؟