اذهب إلى المحتوى

السؤال

نشر


السلام عليكم. جربت اسوي برنامج بسيط باستخدام multiprocessing و الي قراته انه ينفذ المهام بشكل متوازي و لكن ما فهمت لماذا البرنامج ما يوقف و يعطي النتيجة التي اريدها الا اذا استخدمت time.sleep() و قرات ان هذا ليس جيد في multiprocessing لأنه لا يعطي الفائدة من هذه الميزة. انا جديد في استخدام ثريد و ملتي بروسيسينق  غيره و لكن ما فهمت ليش ما تظهر لي النتيجة الا اذا استخدمت أداة time.sleep

 


import multiprocessing
import time
from multiprocessing import Manager



def num(x,y):

    while y.value==False and x!=10:
        x.value+=1
        print(x.value,"\n")
        



def checkNum(x,y):

    while x.value<=10 and y.value==False:
        print(x.value,":")

        if x.value>=10:
            print("x equal or greater than 10\n")
            y.value=True
        elif x.value<10:
            print("x desnt equal or greater than 10\n")
            y.value=False


if __name__ == '__main__':
    manager=Manager()
    x=manager.Value("d",0)
    y = manager.Value("b", False)
    th1=multiprocessing.Process(target=num,args=(x,y))
    th2=multiprocessing.Process(target=checkNum,args=(x,y))

    th1.start()
    th2.start()

    th1.join()
    th2.join()

بدون time.sleep البرنامج يستمر الى ولا يتوقف خصوصا دالة(function) الي اسمها num() 

 

import multiprocessing
import time
from multiprocessing import Manager



def num(x,y):

    while y.value==False and x!=10:
        x.value+=1
        print(x.value,"\n")
        time.sleep(.01) #####



def checkNum(x,y):

    while x.value<=10 and y.value==False:
        print(x.value,":")

        if x.value>=10:
            print("x equal or greater than 10\n")
            y.value=True
        elif x.value<10:
            print("x desnt equal or greater than 10\n")
            y.value=False


if __name__ == '__main__':
    manager=Manager()
    x=manager.Value("d",0)
    y = manager.Value("b", False)
    th1=multiprocessing.Process(target=num,args=(x,y))
    th2=multiprocessing.Process(target=checkNum,args=(x,y))

    th1.start()
    th2.start()

    th1.join()
    th2.join()

هنا مع استخدام time.sleep() لكن في هذه البرنامج يكمل عمله على اكمل وجه و يظهر النتيجة الي اريدها.

هل استخدام time.sleep سيء ام ان في الكود الخاص بي يجب استخدامه لأحصل على النتيجة التي اريدها؟
 

Recommended Posts

  • 1
نشر

وعليكم السلام ورحمة الله وبركاته .

المشكلة التي تحدث لك هي مشكلة مشهورة في تعدد المهام (multi threading) وهي التسابق (race condition) وفي تلك الحالة إذا كان هناك أكثر من عملية process تتعامل مع نفس البيانات فهنا تحدث مشكلة في التسابق . حيث كل عملية تقوم بتعديل القيمة قبل الأخرى وبذلك كل عملية يكون لديها بيانات مختلفة لنفس المتغير .

هنا في دالة num يوجد حلقة تكرار وبداخل تلك الحلقة تقوم بزيادة قيمة x.value . ولكن في دالة checkNum تقوم بالتحقق من تلك القيمة .

هنا يحدث تسابق فتقوم الدالة num بزيادة المتغير بطريقة سريعة جدا . ولكن checkNum لا تستطيع مجاراة ذلك التعديل وبالتالي الدالة checkNum يكون لديها قيم قديمة للمتغير x.value . أى لنفرض أن الدالة num قيمة المتغير x.value وصلت إلى 10000 ولكن بداخل الدالة checkNum قيمة x.value لديها لم تصل إلى ال 10 . وهذا هو سبب المشكلة .

ويمكنك قراءة الإجابات التالية والمقالات لمزيد من التفاصيل حول تلك المشكلة :

 

 

والحل لتلك المشكلة هي القفل Lock . حيث تقوم بقفل هذا المتغير قبل إستخدامه وبهذا إذا أرادت عملية الوصول لهذا المتغير لتعديله أو قراءته لن تستطيع إلا قبل أن يتم إلغاء القفل .

وإليك الكود الصحيح بإستخدام ال Lock :

import multiprocessing
from multiprocessing import Manager

def num(x, y, lock):
    while y.value == False and x.value != 10:
        with lock:
            x.value += 1
        print(x.value, "\n")

def checkNum(x, y, lock):
    while x.value <= 10 and y.value == False:
        with lock:
            print(x.value, ":")
            if x.value >= 10:
                print("x equal or greater than 10\n")
                y.value = True
            else:
                print("x doesn't equal or greater than 10\n")

if __name__ == '__main__':
    manager = Manager()
    x = manager.Value("d", 0)
    y = manager.Value("b", False)
    lock = manager.Lock()  # قفل لمنع الوصول المتزامن للمتغيرات المشتركة
    th1 = multiprocessing.Process(target=num, args=(x, y, lock))
    th2 = multiprocessing.Process(target=checkNum, args=(x, y, lock))

    th1.start()
    th2.start()

    th1.join()
    th2.join()

 

  • 0
نشر
بتاريخ الآن قال محمد عاطف17:

هل يمكنك التوضيح كيف أكبر ؟ 

من المفترض أن يعمل بشكل صحيح كما تريد :

image.png.2e5e59df6868cebbfb5e2395f076b20f.png

اقصد بدون استخدام sleep يظهر بشكل اكبر لدرجة ان رسالة checkNum تختفي من output.

  • 0
نشر
بتاريخ الآن قال Zerious San:

اقصد بدون استخدام sleep يظهر بشكل اكبر لدرجة ان رسالة checkNum تختفي من output.

هل قمت بإستخدام الكود الذي أرفقته لك ؟

يمكنك إستخدامه والتجربة وستجد أن checkNum تطبع الرسائل دون اى مشكلة كما في الصورة التي أرفقتها لك .

إذا لم تستخدم ال Lock أو ال sleep فنعم ستحدث مشكلة التسابق ولن يظهر الرسائل الخاصة بال checkNum

  • 0
نشر
بتاريخ 1 دقيقة مضت قال محمد عاطف17:

هل قمت بإستخدام الكود الذي أرفقته لك ؟

يمكنك إستخدامه والتجربة وستجد أن checkNum تطبع الرسائل دون اى مشكلة كما في الصورة التي أرفقتها لك .

إذا لم تستخدم ال Lock أو ال sleep فنعم ستحدث مشكلة التسابق ولن يظهر الرسائل الخاصة بال checkNum

جربته و ظهرت النتيجة بنفس التي اريد. هل الافضل استخدم lock بدال عن time.sleep؟ لان اريد النظام ان لا يتوقف ام هناك طرق افضل ؟

بتاريخ 51 دقائق مضت قال محمد عاطف17:

وعليكم السلام ورحمة الله وبركاته .

المشكلة التي تحدث لك هي مشكلة مشهورة في تعدد المهام (multi threading) وهي التسابق (race condition) وفي تلك الحالة إذا كان هناك أكثر من عملية process تتعامل مع نفس البيانات فهنا تحدث مشكلة في التسابق . حيث كل عملية تقوم بتعديل القيمة قبل الأخرى وبذلك كل عملية يكون لديها بيانات مختلفة لنفس المتغير .

هنا في دالة num يوجد حلقة تكرار وبداخل تلك الحلقة تقوم بزيادة قيمة x.value . ولكن في دالة checkNum تقوم بالتحقق من تلك القيمة .

هنا يحدث تسابق فتقوم الدالة num بزيادة المتغير بطريقة سريعة جدا . ولكن checkNum لا تستطيع مجاراة ذلك التعديل وبالتالي الدالة checkNum يكون لديها قيم قديمة للمتغير x.value . أى لنفرض أن الدالة num قيمة المتغير x.value وصلت إلى 10000 ولكن بداخل الدالة checkNum قيمة x.value لديها لم تصل إلى ال 10 . وهذا هو سبب المشكلة .

ويمكنك قراءة الإجابات التالية والمقالات لمزيد من التفاصيل حول تلك المشكلة :

 

 

والحل لتلك المشكلة هي القفل Lock . حيث تقوم بقفل هذا المتغير قبل إستخدامه وبهذا إذا أرادت عملية الوصول لهذا المتغير لتعديله أو قراءته لن تستطيع إلا قبل أن يتم إلغاء القفل .

وإليك الكود الصحيح بإستخدام ال Lock :

import multiprocessing
from multiprocessing import Manager

def num(x, y, lock):
    while y.value == False and x.value != 10:
        with lock:
            x.value += 1
        print(x.value, "\n")

def checkNum(x, y, lock):
    while x.value <= 10 and y.value == False:
        with lock:
            print(x.value, ":")
            if x.value >= 10:
                print("x equal or greater than 10\n")
                y.value = True
            else:
                print("x doesn't equal or greater than 10\n")

if __name__ == '__main__':
    manager = Manager()
    x = manager.Value("d", 0)
    y = manager.Value("b", False)
    lock = manager.Lock()  # قفل لمنع الوصول المتزامن للمتغيرات المشتركة
    th1 = multiprocessing.Process(target=num, args=(x, y, lock))
    th2 = multiprocessing.Process(target=checkNum, args=(x, y, lock))

    th1.start()
    th2.start()

    th1.join()
    th2.join()

 

جربت كودك بدون استخدام lock و ضبط ولا صارت مشاكل كيف كذا ؟    :)

المشكلة كانت في num() في شرط if كاتب while y.value==False and x !=10:
نسيت اضع x.value
و المفترض while y.value==False and x.value !=10:

و رجعت المشكلة بعد ما حذفت x.value!=10 حتى في الكود الي رسلت معاه lock. ببحث اكثر عن حل لهذي المشكلة

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...