مكتبة threading
تحتوي مكتبة threading في لغة برمجة Python على العديد من الأدوات والميزات التي تساعد المستخدم على إنشاء وإدارة العمليات المتعددة (Multithreading) في التطبيقات.
تتضمن بعض الميزات المهمة في هذه المكتبة ما يلي:
- إنشاء Threads: يمكن استخدام Thread class في هذه المكتبة لإنشاء threads جديدة في التطبيق.
- Locks: تستخدم الـ Locks لحماية المتغيرات المشتركة بين threads في التطبيق.
- Semaphores: تستخدم Semaphores للسماح بتنفيذ عدد محدد من الـ threads في نفس الوقت.
- Events: تستخدم Events لإعلام threads بوقوع حدث معين في التطبيق.
- Timer: تستخدم Timer لتشغيل functions بانتظام بشكل تلقائي.
- Subclassing Thread: يمكن للمستخدم إنشاء subclasses من Thread class لتنفيذ مهام معينة في التطبيق.
- Daemon Threads: تستخدم daemon threads لتنفيذ tasks غير أساسية في الخلفية دون تأثير على عملية الإيقاف.
هذه بعض الميزات التي تتضمنها مكتبة threading في Python، والتي يمكن استخدامها لإنشاء وإدارة العمليات المتعددة في التطبيقات.
استخدام مكتبة threading
يمكن استخدام مكتبة threading في لغة Python لإنشاء متعدد الخيوط (threads) وتحكم في تنفيذها. يمكن استخدام هذه المكتبة لتسريع تطبيقات الويب والألعاب الحاسوبية عن طريق إنشاء خيوط جديدة لتنفيذ العمليات الثقيلة بصورة مستقلة.
ولاستخدام هذه المكتبة، يجب استيرادها باستخدام الأمر التالي:
import threading
ثم يمكن إنشاء خيوط جديدة باستخدام الدالة Thread() :
t = threading.Thread(target=my_function)
حيث my_function هي الدالة التي تريد تنفيذها داخل الخيط. ثم يمكن
تشغيل الخيط باستخدام الأمر start() :
t.start()
يمكن التحكم في سير الخيط باستخدام الدوال الخاصة بالمكتبة مثل
join() لانتظار انتهاء الخيط و is_alive() للتحقق من حالة الخيط (منشغل أم لا).
دوال مكتبة threading
مكتبة threading في لغة Python توفر دعماً للتعامل مع المهام المتعددة بشكل موازي وفعّال. هناك العديد من الدوال المهمة في هذه المكتبة، ومن بينها:
threading.Thread
تُستخدم لإنشاء خيط جديد.
start()
تستخدم لبدء تشغيل خيط.
join([time])
تستخدم لانتظار انتهاء تشغيل الخيط، ويمكن تحديد المدة الزمنية التي يجب
فيها الانتظار عن طريق تحديد قيمة معينة للمتغير time.
is_alive()
تستخدم للتحقق مما إذا كان الخيط ما زال يعمل أم لا.
enumerate()
تستخدم لاسترداد قائمة بجميع الخيوط الفعّالة في الوقت الحالي.
active_count()
تستخدم لاسترداد عدد الخيوط الفعّالة في الوقت الحالي.
Lock()
تستخدم لتأمين المتغيرات المشتركة بين الخيوط.
RLock()
تستخدم لتطبيق نظام إدارة الأقفال ذات المستوى المتعدد (re-entrant
lock).
Condition()
تستخدم لإنشاء شرط يجمع بين Lock وWait.
Semaphore()
تستخدم لتحديد عدد محدد من الخيوط التي يمكنها العمل في نفس الوقت.
is_alive()
is_alive() هي وظيفة تستخدم في برمجة متعددة الخيوط (Multithreading) في بايثون للتحقق من حالة تشغيل خيط (Thread) ما. تُستخدم الوظيفة is_alive() للتحقق مما إذا كان الخيط يعمل أو توقف عن العمل.
وهناك طريقتان لاستخدام الوظيفة is_alive() في بايثون. الأولى هي استدعاء
الوظيفة مباشرة على كائن Thread، على سبيل المثال:
import threading
thread = threading.Thread(target=my_function)
thread.start()
if thread.is_alive():
print("Thread is running")
else:
print("Thread is not running")
والثانية هي استخدام الوظيفة join() للانتظار حتى ينتهي الخيط قبل
التحقق من حالته، على سبيل المثال:
import threading
thread = threading.Thread(target=my_function)
thread.start()
thread.join()
if thread.is_alive():
print("Thread is running")
else:
print("Thread is not running")
في هذه الحالة، سينتظر البرنامج حتى ينتهي الخيط thread قبل القيام
بالتحقق من حالته باستخدام is_alive() ، وذلك بفضل استخدام الوظيفة join() .
threading.Thread
threading.Thread هي فئة مدمجة في لغة Python وتستخدم لإنشاء خيوط (threads) جديدة. تسمح الخيوط بتنفيذ عمليات متعددة في نفس الوقت بدلاً من تنفيذها بشكل تسلسلي واحد تلو الآخر.
يمكن استخدام threading.Thread لإنشاء كائن Thread جديد، والذي يأخذ وظيفة
أو طريقة كمدخلات. عند بدء التشغيل، سيتم تنفيذ الوظيفة في خط منفصل، ويمكن
التحكم في تنفيذ الخيط باستخدام الميزات المدمجة في threading ، مثل lock و Event
.
فيما يلي مثال بسيط لاستخدام threading.Thread :
import threading
def worker():
"""The thread worker function."""
print('Worker')
# Create a new thread
t = threading.Thread(target=worker)
# Start the thread
t.start()
# Wait for the thread to finish
t.join()
print('Done')
في هذا المثال، يتم إنشاء وظيفة worker التي تطبع "Worker". ثم يتم
إنشاء Thread جديد ويتم تعيين المدخل target إلى الوظيفة worker . يتم بعد ذلك
بدء التشغيل باستخدام start() ، ثم يستخدم join() لانتظار انتهاء التنفيذ.
أخيرًا، يطبع "Done".
enumerate()
enumerate() هي وظيفة مدمجة في لغة البرمجة بايثون والتي تأخذ مجموعة (قائمة، tuple، إلخ) كمدخل وترجع تسلسلًا من الأزواج التي تتكون من مؤشر العنصر والعنصر نفسه. على سبيل المثال،
my_list = ['apple', 'banana', 'orange']
for index, fruit in enumerate(my_list):
print(index, fruit)
ستخرج النتيجة:
0 apple
1 banana
2 orange
يمكن استخدام enumerate() في أي حالة تحتاج فيها إلى حلقة تكرارية
وتحتاج إلى مؤشر للعنصر الحالي في التسلسل.
active_count()
active_count() هي دالة في لغة بايثون (Python) تستخدم للحصول على عدد الثريدات (threads) الفعّالة (active threads) في مجموعة الثريدات. وهذا يشير إلى عدد الثريدات التي لم تكتمل بعد والتي لا تزال قيد التنفيذ.
لإستخدام active_count() ، يجب استيراد المكتبة threading ثم إنشاء مجموعة
من الثريدات ومن ثم استدعاء الدالة active_count() على هذه المجموعة.
فيما يلي مثال بسيط يوضح كيفية استخدام active_count() :
import threading
def my_func():
print("Hello from thread")
# انشاء مجموعة من الثريدات
my_threads = []
for i in range(5):
t = threading.Thread(target=my_func)
my_threads.append(t)
# بدء تنفيذ الثريدات
for t in my_threads:
t.start()
# الحصول على عدد الثريدات الفعّالة
count = threading.active_count()
print("Active threads:", count)
ستظهر النتيجة في هذا المثال عدد الثريدات الفعّالة في المجموعة بعد
بدء تنفيذ الثريدات
Lock()
Lock() هي وظيفة في بايثون تستخدم لتأمين الوصول إلى الموارد الخاصة بالمتغيرات المشتركة عند استخدام المسارات المتعددة (Multithreading). يتم استخدامها لإنشاء قفل على مصادر المتغيرات المشتركة ، حيث يمنع الوصول إلى المورد من أي مسار آخر حتى يتم إطلاق القفل. يتم إنشاء قفل باستخدام العبارة التالية:
lock = threading.Lock()
ثم يمكن تأمين الوصول إلى المتغيرات المشتركة باستخدام القفل
باستخدام العبارة التالية:
lock.acquire()
# Critical section - shared resources
lock.release()
سيتم قفل القفل عند استخدام lock.acquire() ، وسيتم فتح القفل
والسماح للمسارات الأخرى بالوصول إلى الموارد المشتركة عند استخدام
lock.release() .
RLock()
RLock() هو نوع من الأقفال في بايثون وهو يستخدم لتجنب تداخل الموارد في بيئة متعددة المهام. حيث يسمح لك RLock() بإنشاء أقفال قابلة للاستخدام مرات عديدة من قبل نفس الخط الزمني (Thread)، وبالتالي يمكن لنفس الخط الزمني يمتلك الأقفال التي يمتلكها، ويمكنه أيضًا إضافة الأقفال التي يمتلكها.
عند استخدام RLock()، يتم اكتساب الأقفال داخل الخط الزمني بواسطة خط الزمني نفسه، وهذا يعني أنه يمكن للخط الزمني الحصول على الأقفال التي يمتلكها بالفعل دون الحاجة إلى استنفادها. ومن المهم ملاحظة أن RLock() يجب استخدامه فقط إذا كانت هناك حاجة لمجموعة من الأقفال المملوكة بواسطة نفس الخط الزمني. يمكن استخدام Lock() أو Semaphore() إذا كانت هناك حاجة فقط لأقفال فريدة لاستخدامها من قبل خط زمني واحد.
Condition()
Condition() في بايثون هي وظيفة تستخدم للتحقق من حالة معينة قبل استئناف تنفيذ الكود. يمكن استخدامها في برامج متعددة المهام للتزامن بين عمليات مختلفة.
تأخذ Condition() عادةً مسارًا (path) وتستخدم لإشعار العمليات الأخرى
عندما يصبح المسار متاحًا. على سبيل المثال، يمكن استخدام Condition() للتحقق من
إذن كائن مشترك (shared object) لضمان أنه لا يتم الوصول إليه من عملية أخرى قبل
الانتهاء من العملية الحالية.
للاستفادة من Condition() ، يمكن استيرادها من وحدة threading في بايثون:
from threading import Condition
# create a condition object
condition = Condition()
# use the condition in your code to synchronize between threads
يمكن استخدام دالة acquire() لاحتجاز القفل (lock) قبل التحقق من
الشرط، ثم استخدام دالة notify_all() لإشعار جميع العمليات الأخرى بأن المسار
متاح.
Semaphore()
Semaphore() هي وظيفة في لغة بايثون الخاصة بإنشاء Semaphore (مؤشر اتجاه) والذي يستخدم عادةً في التحكم في الوصول إلى المورد بين المهام المتعددة (multi-threading) أو العمليات المتعددة (multi-processing).
يمكن استدعاء Semaphore() مع عدد صحيح كبير يمثل الحد الأقصى للموارد التي
يمكن الوصول إليها في نفس الوقت. وعند استخدام Semaphore، يتم تمريره كمعامل إلى
دوال الإفراج عن المورد (release()) والاحتفاظ به (acquire()).
فيما يلي مثال بسيط يستخدم Semaphore() لتحديد الموارد المتاحة للوصول إلى
شريط التقدم (progress bar):
import threading
class ProgressBar:
def __init__(self, max_val)
self.curr_val = 0
self.max_val = max_val
self.progress_sem = threading.Semaphore(1)
def increment(self):
self.progress_sem.acquire()
self.curr_val += 1
self.update()
self.progress_sem.release()
def update(self):
progress_str = "[" + "#" * self.curr_val + "-" * (self.max_val - self.curr_val) + "]"
print(progress_str)
if __name__ == "__main__":
pb = ProgressBar(10)
for i in range(1, 11):
pb.increment()
في هذا المثال، تم إنشاء ProgressBar الذي يستخدم Semaphore لضمان
أنه يتم تحديث قيمة curr_val بطريقة آمنة عند استدعاء دالة increment() من مهام
متعددة في نفس الوقت.