0Pricing
Python Academy · درس

الخيوط وGIL

افهم حدود استخدام الخيوط في Python

الخيوط وGIL درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.

ما الخيط؟

الخيط هو مسار منفصل للتنفيذ داخل عملية واحدة. تتيح وحدة threading في Python تشغيل الدوال بالتزامن ضمن برنامج واحد.

import threading

def worker():
    print('hello from thread')

t = threading.Thread(target=worker)
t.start()
t.join()
print('main done')

بدء عدة خيوط

يمكنكم تشغيل عدة خيوط، وينفّذ كل منها دالته المستهدفة. تجعل join() الخيط الرئيسي ينتظر حتى ينتهي الخيط.

import threading

def task(name):
    print('task', name)

threads = [threading.Thread(target=task, args=(i,)) for i in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print('all finished')

قفل المفسّر العام

تحتوي CPython على قفل المفسّر العام (GIL): لا ينفّذ أكثر من خيط واحد بايت كود Python في الوقت نفسه. وهذا يعني أن الخيوط لا توفّر تسريعًا متوازيًا حقيقيًا للأعمال التي تعتمد على CPU وتُنفَّذ بالكامل في Python.

import sys
print('Running on:', sys.implementation.name)
print('Only one thread runs Python bytecode at a time due to the GIL')

متى تظل الخيوط مفيدة

تتألق الخيوط في الأعمال المقيّدة بالإدخال والإخراج (I/O-bound)، مثل طلبات الشبكة وقراءة الأقراص والانتظار. فعندما ينتظر أحد الخيوط، يُحرَّر GIL ويمكن لخيط آخر أن يعمل.

import threading, time

def fake_io(name):
    time.sleep(0.1)
    print('done', name)

start = time.perf_counter()
ts = [threading.Thread(target=fake_io, args=(i,)) for i in range(3)]
for t in ts: t.start()
for t in ts: t.join()
print('elapsed about 0.1s, not 0.3s')

العمل المقيّد بالمعالج لا يتسارع

لن تؤدي إضافة الخيوط إلى تسريع الحسابات الثقيلة، لأن GIL ينفّذها بالتتابع. استخدموا multiprocessing بدلًا من ذلك للأعمال التي تعتمد على CPU.

import threading

def burn():
    total = 0
    for i in range(1000000):
        total += i
    return total

t = threading.Thread(target=burn)
t.start()
t.join()
print('CPU-bound: threads share one core under the GIL')

الخيوط الخفية

يتوقف خيط daemon تلقائيًا عند انتهاء البرنامج الرئيسي. استخدموه للمساعدات التي تعمل في الخلفية ولا تحتاجون إلى انتظارها.

import threading, time

def background():
    time.sleep(0.05)
    print('background tick')

t = threading.Thread(target=background, daemon=True)
t.start()
t.join()
print('main exits')

تسمية الخيوط والتعرّف إليها

لكل خيط اسم ومعرّف. تعيد threading.current_thread() كائن الخيط قيد التشغيل، وهو مفيد للتسجيل.

import threading

def show():
    t = threading.current_thread()
    print('running in', t.name)

t = threading.Thread(target=show, name='Worker-1')
t.start()
t.join()
print('main thread:', threading.current_thread().name)

إنشاء فئة فرعية من Thread

بدلًا من تمرير target، يمكنكم إنشاء فئة فرعية من Thread وتجاوز run(). ويفيد ذلك عندما يحتاج الخيط إلى حالته الخاصة.

import threading

class Greeter(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.who = name
    def run(self):
        print('hi', self.who)

g = Greeter('Sam')
g.start()
g.join()

إعادة النتائج من الخيوط

تُهمَل القيمة المُعادة من الدالة المستهدفة. ولجمع النتائج، اكتبواها في بنية مشتركة، وستتعرفون لاحقًا إلى أدوات أكثر أمانًا مثل قوائم الانتظار.

import threading

results = {}

def compute(key):
    results[key] = key * key

ts = [threading.Thread(target=compute, args=(i,)) for i in range(4)]
for t in ts: t.start()
for t in ts: t.join()
print(results)

عدّ الخيوط النشطة

تُخبركم threading.active_count() بعدد الخيوط النشطة حاليًا، بما في ذلك الخيط الرئيسي.

import threading, time

def wait():
    time.sleep(0.05)

ts = [threading.Thread(target=wait) for _ in range(2)]
for t in ts: t.start()
print('active now:', threading.active_count())
for t in ts: t.join()
print('active after join:', threading.active_count())

اختيار الخيوط أم العمليات

قاعدة عامة: استخدموا الخيوط للتزامن في الأعمال المقيّدة بالإدخال والإخراج، والعمليات للتوازي في الأعمال المقيّدة بالمعالج. وGIL هو السبب.

tasks = {'download files': 'threads', 'crunch numbers': 'processes', 'call APIs': 'threads'}
for task, choice in tasks.items():
    print(task, '->', choice)

اختبار سريع

اختبروا مدى فهمكم للخيوط وGIL.

مراجعة

لقد تعلمتم عن الخيوط وGIL:

  • تعمل الخيوط بالتزامن داخل عملية واحدة عبر threading.Thread.
  • يفرض GIL تنفيذ بايت كود Python بالتتابع.
  • تفيد الخيوط الأعمال المقيّدة بالإدخال والإخراج، وتفيد العمليات الأعمال المقيّدة بالمعالج.
  • استخدموا start() وjoin() والخيوط الخفية وإنشاء الفئات الفرعية.

التالي: إدارة الخيوط بطريقة منظمة باستخدام ThreadPoolExecutor.

الأسئلة الشائعة

هل درس «الخيوط وGIL» مجاني؟

نعم — نص درس «الخيوط وGIL» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.

ماذا ستتعلم في «الخيوط وGIL»؟

افهم حدود استخدام الخيوط في Python تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟

لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «الخيوط وGIL»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟

نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الخيوط وGIL
  2. ThreadPoolExecutor
  3. أساسيات multiprocessing
  4. مشاركة البيانات بأمان
← العودة إلى Python Academy