أساسيات multiprocessing
استخدم عدة أنوية للمعالج
أساسيات multiprocessing درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.
لماذا multiprocessing؟
يمنع GIL الخيوط من تنفيذ بايت كود Python بالتوازي. وتتجاوز وحدة multiprocessing ذلك من خلال تشغيل عمليات منفصلة، لكل منها مفسّرها الخاص وGIL الخاص بها، ولذلك تُنفَّذ المهام المرتبطة بوحدة المعالجة المركزية فعليًا على عدة أنوية.
import multiprocessing as mp
print('CPU cores available:', mp.cpu_count())بدء تشغيل عملية
تحاكي Process(target=func) واجهة برمجة التطبيقات الخاصة بالخيوط. استدعوا start() لبدء التشغيل، وjoin() للانتظار.
import multiprocessing as mp
def worker():
print('hello from a child process')
if __name__ == '__main__':
p = mp.Process(target=worker)
p.start()
p.join()
print('parent done')حارس __main__
في بعض المنصات، تستورد العمليات الابنة البرنامج النصي الخاص بكم. ومن دون حارس if __name__ == '__main__':، قد تنشئون عمليات بشكل متكرر. احرصوا دائمًا على وضع رمز التشغيل داخل هذا الحارس.
import multiprocessing as mp
def task(n):
print('processing', n)
if __name__ == '__main__':
for i in range(3):
p = mp.Process(target=task, args=(i,))
p.start()
p.join()تمرير الوسائط
استخدموا args للوسائط الموضعية وkwargs للوسائط المسمّاة، تمامًا كما هو الحال مع الخيوط. تُحوَّل الوسائط إلى pickle وتُرسَل إلى العملية الابنة.
import multiprocessing as mp
def show(label, times):
for _ in range(times):
print(label)
if __name__ == '__main__':
p = mp.Process(target=show, args=('hi',), kwargs={'times': 2})
p.start()
p.join()مجموعة من العاملين
تدير multiprocessing.Pool مجموعة من العمليات. وتوزّع pool.map العناصر القابلة للتكرار بينها، ثم تجمع النتائج بالترتيب.
import multiprocessing as mp
def square(n):
return n * n
if __name__ == '__main__':
with mp.Pool(processes=2) as pool:
print(pool.map(square, range(6)))ProcessPoolExecutor
توفر واجهة برمجة التطبيقات concurrent.futures أيضًا ProcessPoolExecutor، مع واجهة submit/map نفسها التي رأيتموها مع الخيوط.
from concurrent.futures import ProcessPoolExecutor
def cube(n):
return n ** 3
if __name__ == '__main__':
with ProcessPoolExecutor() as ex:
print(list(ex.map(cube, range(5))))مساحات ذاكرة منفصلة
لكل عملية ذاكرتها الخاصة. ولا يؤدي تعديل متغير عام في عملية ابنة إلى تغيير نسخته في العملية الأب. يجب إعادة البيانات أو مشاركتها بشكل صريح.
import multiprocessing as mp
counter = 0
def bump():
global counter
counter += 100
if __name__ == '__main__':
p = mp.Process(target=bump)
p.start()
p.join()
print('parent counter still:', counter)استعادة النتائج
بما أن الذاكرة غير مشتركة، أعيدوا النتائج من خلال Pool.map أو المنفّذات أو قوائم الانتظار بدلًا من تعديل المتغيرات العامة.
import multiprocessing as mp
def double(n):
return n * 2
if __name__ == '__main__':
with mp.Pool(2) as pool:
results = pool.map(double, [1, 2, 3, 4])
print('results:', results)apply_async للاستدعاءات الفردية
يجدول apply_async استدعاءً واحدًا ويعيد مقبضًا للنتيجة. استدعوا .get() لاسترداد القيمة.
import multiprocessing as mp
def add(a, b):
return a + b
if __name__ == '__main__':
with mp.Pool(2) as pool:
r = pool.apply_async(add, (3, 4))
print(r.get())متطلب Pickle
يجب أن تكون الأهداف والوسائط قابلة للتسلسل باستخدام pickle حتى تتمكن من عبور حدود العمليات. تعمل الدوال المعرّفة في المستوى الأعلى، أما الدوال المجهولة والدوال المحلية فعادةً لا تعمل.
import multiprocessing as mp
def top_level(n):
return n + 1
if __name__ == '__main__':
with mp.Pool(2) as pool:
print(pool.map(top_level, [10, 20]))متى تستخدمون العمليات
استخدموا العمليات للمهام كثيفة الاستخدام لوحدة المعالجة المركزية، مثل الرياضيات ومعالجة الصور والتحليل. ونظرًا إلى تكلفة إنشاء العمليات وتحويل البيانات إلى pickle، فهي مناسبة لعدد أقل من المهام الأثقل، لا لعدد كبير من المهام الصغيرة جدًا.
import multiprocessing as mp
def heavy(n):
return sum(i * i for i in range(n))
if __name__ == '__main__':
with mp.Pool() as pool:
print(pool.map(heavy, [1000, 2000, 3000]))تحقق سريع
اختبروا مدى فهمكم لـ multiprocessing.
مراجعة
لقد تعلّمتم أساسيات multiprocessing:
- تتجاوز العمليات GIL لتحقيق توازٍ حقيقي للمهام المرتبطة بالمعالج.
- استخدموا الحارس
if __name__ == '__main__'. - توزّع
PoolوProcessPoolExecutorالعمل وتجمع النتائج. - الذاكرة غير مشتركة، ويجب أن تكون الوسائط قابلة للتسلسل باستخدام pickle.
التالي: مشاركة البيانات بأمان باستخدام قوائم الانتظار والأقفال.
الأسئلة الشائعة
هل درس «أساسيات multiprocessing» مجاني؟
نعم — نص درس «أساسيات multiprocessing» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.
ماذا ستتعلم في «أساسيات multiprocessing»؟
استخدم عدة أنوية للمعالج تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟
لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «أساسيات multiprocessing»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟
نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الخيوط وGIL
- ThreadPoolExecutor
- أساسيات multiprocessing
- مشاركة البيانات بأمان