0Pricing
Python Academy · درس

مشاركة البيانات بأمان

استخدم قوائم الانتظار والأقفال

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

مشكلة حالة التسابق

عندما تعدّل خيوط متعددة البيانات نفسها، قد تتداخل عملياتها، مما يؤدي إلى إفساد النتيجة. تُسمّى هذه الحالة حالة تسابق. نحتاج إلى أدوات مزامنة لمشاركة البيانات بأمان.

import threading

counter = 0

def bump():
    global counter
    for _ in range(100000):
        counter += 1

ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter (may be < 200000):', counter)

القفل هو الحل

يضمن threading.Lock دخول خيط واحد فقط إلى قسم حرج في كل مرة. احصلوا عليه باستخدام كتلة with حول تحديث البيانات المشتركة.

import threading

counter = 0
lock = threading.Lock()

def bump():
    global counter
    for _ in range(100000):
        with lock:
            counter += 1

ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter:', counter)

acquire و release

يمكن استخدام القفل يدويًا باستدعاء acquire() وrelease()، لكن صيغة with أكثر أمانًا لأنها تحرر القفل حتى في حال وقوع خطأ.

import threading

lock = threading.Lock()
lock.acquire()
try:
    print('inside critical section')
finally:
    lock.release()
print('released')

قوائم انتظار آمنة للخيوط

إن الفئة queue.Queue آمنة للخيوط أصلًا. يمكن للخيوط استخدام put وget من دون أقفال صريحة، مما يجعلها الطريقة المفضلة لتمرير البيانات.

import queue, threading

q = queue.Queue()

def producer():
    for i in range(3):
        q.put(i)

t = threading.Thread(target=producer)
t.start()
t.join()
while not q.empty():
    print('got', q.get())

المنتِج والمستهلك

النمط التقليدي هو أن يضع المنتِجون العمل في قائمة انتظار باستخدام put، ثم يسترده المستهلكون باستخدام get ويعالجونه. وتتولى قائمة الانتظار جميع عمليات القفل.

import queue, threading

q = queue.Queue()
results = []

def consumer():
    while True:
        item = q.get()
        if item is None:
            break
        results.append(item * 10)
        q.task_done()

t = threading.Thread(target=consumer)
t.start()
for i in range(3):
    q.put(i)
q.put(None)
t.join()
print(results)

join و task_done

يحجب q.join() التنفيذ حتى يتلقى كل عنصر أُضيف باستخدام put استدعاءً مطابقًا لـ task_done(). يتيح ذلك للخيط الرئيسي الانتظار حتى يكتمل كل العمل.

import queue, threading

q = queue.Queue()

def worker():
    while True:
        item = q.get()
        q.task_done()

threading.Thread(target=worker, daemon=True).start()
for i in range(5):
    q.put(i)
q.join()
print('all items processed')

RLock لإعادة الدخول

يؤدي Lock العادي إلى حالة تعطل متبادل إذا حاول الخيط نفسه الحصول عليه مرتين. أما threading.RLock (القفل القابل لإعادة الدخول) فيسمح بذلك، مع احتساب مرات الحصول عليه.

import threading

rlock = threading.RLock()

def outer():
    with rlock:
        inner()

def inner():
    with rlock:
        print('re-entered safely')

outer()

Event لإرسال الإشارات

يتيح threading.Event لخيط واحد إرسال إشارة إلى خيوط أخرى. تستدعي الخيوط wait() إلى أن يستدعي خيط آخر set().

import threading

start = threading.Event()

def worker():
    start.wait()
    print('go!')

t = threading.Thread(target=worker)
t.start()
print('setting event')
start.set()
t.join()

المشاركة بين العمليات

بين العمليات، استخدموا multiprocessing.Queue بدلًا من ذلك. فهي تحوّل الكائنات إلى صيغة قابلة للإرسال بين مساحات الذاكرة المنفصلة.

import multiprocessing as mp

def producer(q):
    for i in range(3):
        q.put(i * i)

if __name__ == '__main__':
    q = mp.Queue()
    p = mp.Process(target=producer, args=(q,))
    p.start()
    p.join()
    while not q.empty():
        print('received', q.get())

تجنب التعطل المتبادل

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

import threading

lock_a = threading.Lock()
lock_b = threading.Lock()

def safe():
    with lock_a:
        with lock_b:
            print('acquired in consistent order')

safe()

فضّلوا قوائم الانتظار على الأقفال

متى أمكن، فضّلوا تمرير الرسائل باستخدام قوائم الانتظار على الحالة المشتركة القابلة للتعديل والمحميّة بالأقفال. فهذا أسهل في الفهم وأقل عرضة للأخطاء بكثير.

import queue

q = queue.Queue()
for word in ['safe', 'simple', 'clear']:
    q.put(word)
while not q.empty():
    print(q.get())

تحقق سريع

اختبروا مدى فهمكم لمشاركة البيانات بأمان.

مراجعة

لقد تعلّمتم مشاركة البيانات بأمان:

  • تؤدي حالات التسابق إلى إفساد الحالة المشتركة غير المحميّة.
  • يحمي Lock وRLock الأقسام الحرجة.
  • إن queue.Queue آمنة للخيوط، بينما تُستخدم multiprocessing.Queue بين العمليات.
  • ترسل Event إشارات بين الخيوط، ويؤدي توحيد ترتيب الأقفال إلى تجنب التعطل المتبادل.

الدورة التالية: تشغيل البرامج الخارجية باستخدام subprocess.

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

هل درس «مشاركة البيانات بأمان» مجاني؟

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

ماذا ستتعلم في «مشاركة البيانات بأمان»؟

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

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

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

كم من الوقت يستغرق درس «مشاركة البيانات بأمان»؟

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

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

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

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

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