مقدمة في تعدد المهام وتعدد العمليات في بايثون
عند تطوير التطبيقات الحديثة، غالبًا ما تحتاج إلى تحسين الأداء. يتم تحقيق ذلك من خلال تنفيذ المهام بشكل متوازٍ. في بايثون، تُستخدم أدوات مثل تعدد المهام (multithreading) وتعدد العمليات (multiprocessing) لتحقيق ذلك. على الرغم من وجود قفل المفسر العام (GIL)، إلا أن تعدد المهام في بايثون يمكنه تسريع البرامج بشكل كبير، خاصة في المهام التي تعتمد على الإدخال والإخراج (I/O) مثل طلبات الشبكة أو التعامل مع الملفات.
في هذا الدليل، سنشرح كيفية عمل تعدد المهام في بايثون. سنستعرض مكتبة threading، ونقارنها بـ multiprocessing، ونقدم أمثلة عملية. سيساعدك هذا على فهم كيفية تحسين الكود لتسريع التنفيذ.
ما هو تعدد المهام في بايثون
يتيح لك تعدد المهام في بايثون تشغيل عدة خيوط (threads) داخل عملية واحدة. كل خيط ينفذ جزءًا من الكود بشكل متوازٍ. هذا الأسلوب فعال للمهام التي تتضمن انتظار موارد خارجية.
مزايا تعدد المهام لمهام الإدخال والإخراج
يعمل تعدد المهام على تسريع البرامج عندما تشمل المهام:
- طلبات الشبكة، مثل تحميل البيانات من الإنترنت.
- التعامل مع الملفات، بما في ذلك القراءة والكتابة.
- الوصول إلى قواعد البيانات.
- عمليات الإدخال والإخراج الأخرى حيث يظل المعالج خاملاً في انتظار.
ومع ذلك، فإن تعدد المهام له قيود. في بايثون، يوجد قفل المفسر العام (GIL). يمنع GIL التنفيذ المتزامن للبايت كود (bytecode) في عدة خيوط. ولهذا السبب، لا يناسب تعدد المهام المهام كثيفة الحساب التي تتطلب تحميلًا كاملاً لوحدة المعالجة المركزية (CPU).
متى تستخدم تعدد المهام أو تعدد العمليات
يعتمد الاختيار بين تعدد المهام وتعدد العمليات على نوع المهام. تعدد المهام مناسب لسيناريوهات الانتظار، بينما تعدد العمليات مناسب للحسابات.
توصيات حسب السيناريو
- المهام كثيفة الإدخال والإخراج: استخدم threading (الخيوط) لتجنب حظر الخيط الرئيسي.
- المهام كثيفة الحساب: استخدم multiprocessing (العمليات) لتجاوز GIL والاستفادة من عدة أنوية CPU.
- التعامل مع واجهات برمجة التطبيقات (APIs) الشبكية: اختر threading لمعالجة الطلبات بكفاءة.
- معالجة البيانات المتوازية: من الأفضل استخدام multiprocessing لتوزيع الحمل على المعالجات.
يساعدك هذا الأسلوب في تجنب الاستخدام غير الفعال للموارد وتسريع تنفيذ البرنامج.
مكتبة threading: الأساسيات والأمثلة
توفر مكتبة threading في بايثون أدوات لإنشاء وإدارة الخيوط. إنها سهلة الاستخدام ومناسبة للمبتدئين.
مثال بسيط لإنشاء خيط
إليك مثال أساسي لتعدد المهام في بايثون:
import threading
import time
def print_numbers():
for i in range(5):
print(f"الرقم: {i}")
time.sleep(1)
# إنشاء خيط
thread = threading.Thread(target=print_numbers)
thread.start()
# يستمر الخيط الرئيسي
print("تم إنهاء الخيط الرئيسي!")
في هذا الكود، ينتهي الخيط الرئيسي فورًا، بينما يتم تنفيذ الدالة print_numbers في خيط منفصل. يوضح هذا كيف يسمح تعدد المهام بمواصلة العمل دون انتظار.
تمرير الوسائط إلى الخيط
لتمرير البيانات إلى دالة الخيط، استخدم المعامل args:
def greet(name):
print(f"مرحبًا، {name}!")
thread = threading.Thread(target=greet, args=("أحمد",))
thread.start()
هنا، يتم تمرير الوسيط "أحمد" إلى الدالة greet. هذا مفيد لتحديد معلمات المهام في الخيوط.
انتظار انتهاء الخيوط باستخدام join
تتيح لك طريقة join انتظار انتهاء الخيط قبل متابعة التنفيذ:
thread.join()
print("تم انتظار انتهاء الخيط")
يضمن هذا أن الخيط الرئيسي ينتظر حتى يكتمل الخيط الفرعي، وهو أمر ضروري عند الحاجة إلى نتائج الخيط.