تتضمن جدولة المهام إعداد المهام والوظائف التي يمكن تشغيلها في أوقات أو فترات زمنية محددة. كما يتضمن أيضًا معالجة متكررة تضمن الاستخدام الفعال للموارد.
في هذا البرنامج التعليمي، سوف نتعلم أساسيات إعداد وبناء تطبيقات جدولة المهام باستخدام لغة البرمجة Go.
ما هي جدولة المهام؟
تشير جدولة المهام إلى عملية تخطيط وتنفيذ المهام أو الوظائف في أوقات محددة أو استجابة لأحداث معينة.
تعد جدولة المهام أمرًا أساسيًا في مختلف المجالات بما في ذلك إدارة النظام ومعالجة البيانات وتطبيقات الويب والمزيد.
في Go، يمكننا العمل مع آلية جدولة المهام باستخدام goroutines وهي في الأساس خيوط تنفيذ خفيفة الوزن يمكنها تشغيل المهام بطريقة متزامنة.
أنواع جدولة المهام
يمكننا تصنيف جدولة المهام إلى مجموعات مختلفة بناءً على معايير التنفيذ. تتضمن مهام جدولة المهام ما يلي:
- الجدولة المستندة إلى الوقت - يشير هذا إلى المهام التي تمت جدولتها للتشغيل في أوقات أو فترات زمنية محددة. ومن الأمثلة على ذلك النسخ الاحتياطية الدورية، ووظائف cron، وما إلى ذلك.
- الجدولة المستندة إلى الأحداث - تشير المهام المستندة إلى الأحداث إلى المهام التي يتم تشغيلها بواسطة مهام أو ظروف محددة مثل قراءة المستشعر، أو الرسائل من النظام الخارجي، وما إلى ذلك.
- الجدولة على أساس الأولوية - لدينا جدولة على أساس الأولوية حيث يتم تنفيذ المهام ذات الأولوية العليا أولاً قبل المهام ذات الأولوية الأقل.
- الجدولة القائمة على التبعية – في الجدولة القائمة على التبعية، يكون للمهام تبعيات على مهام أخرى ويتم تنفيذها في تسلسل يرضي هذه التبعيات.
مع ذلك، دعونا نناقش جدولة المهام في Go.
الذهاب التزامن
إحدى الميزات الأكثر شهرة في لغة البرمجة Go هي دعمها الممتاز للتزامن مما يجعلها فعالة للغاية لإنشاء تطبيقات متزامنة للغاية.
هناك نوعان من البدائيات الرئيسية في لغة Go لتوفير الدعم للتزامن: goroutines والقنوات.
جوروتينس
goroutine عبارة عن سلسلة تنفيذ خفيفة الوزن تتم إدارتها بواسطة وقت تشغيل Go. توفر Goroutines ميزات أكثر كفاءة وأمانًا مقارنة بالخيوط التقليدية.
في Go، يمكننا إنشاء goroutine باستخدام الكلمة الأساسية 'go' قبل استدعاء دالة كما هو موضح في ما يلي:
func الرئيسي ( ) {الذهاب وظيفة ( )
// ...
}
يجب أن يؤدي هذا إلى إنشاء نظام goroutine ينفذ الوظيفة المسماة 'func' بطريقة متزامنة.
القنوات
من ناحية أخرى، تعد القنوات آلية قوية جدًا توفر الاتصال والمزامنة بين goroutines.
يتمثل دور القنوات في توفير وسائل مشاركة البيانات ومزامنتها بشكل آمن دون الحاجة إلى استخدام الأقفال.
في Go، يمكننا إنشاء قناة باستخدام الكلمة الأساسية 'chan'. ومن هناك، يمكننا استخدام القنوات لإرسال أو استقبال البيانات بين الإجراءات.
الفصل := يصنع ( تشان كثافة العمليات )يجب أن يؤدي هذا إلى إنشاء قناة عدد صحيح.
جدولة المهام في الذهاب
الآن بعد أن أصبح لدينا فهم أساسي للميزات المتزامنة لـ Go، دعونا نتعلم كيفية استخدامها لجدولة المهام.
استخدام Goroutines والقنوات
يتضمن الأساس الأساسي والقوي لجدولة المهام في Go استخدام goroutines والقنوات.
يمكننا إنشاء goroutines لتنفيذ المهام بشكل متزامن واستخدام القنوات للتواصل فيما بينها.
خذ بعين الاعتبار مثالًا أساسيًا كما هو موضح في ما يلي:
الحزمة الرئيسيةيستورد (
'إف إم تي'
'وقت'
)
مهمة func ( سلسلة الاسم ) {
وقت النوم ( 5 * الوقت.الثانية )
fmt.Println ( 'مهمة' ، اسم، 'مكتمل.' )
}
func الرئيسي ( ) {
المهام := [ ] خيط { 'مهمة 1' , 'Task2' , 'Task3' , 'المهمة4' }
ل _، اسم المهمة:= نطاق المهام {
اذهب المهمة ( اسم المهمة )
}
وقت النوم ( 8 * الوقت.الثانية )
}
في هذا المثال، لدينا goroutines التي تنفذ المهام بشكل متزامن. نستخدم أيضًا الدالة time.Sleep() لمدة خمس ثوانٍ لمحاكاة عمل المهمة.
ثم ينتظر البرنامج حتى تكتمل جميع المهام باستخدام time.Sleep().
الجدولة على أساس الموقت
تتضمن الجدولة المستندة إلى المؤقت تنفيذ المهام في أوقات محددة أو بعد مدة معينة. يوفر Go حزمة الوقت للعمل مع أجهزة ضبط الوقت.
خذ بعين الاعتبار المثال التالي الذي يوضح كيفية جدولة مهمة ليتم تشغيلها بعد تأخير:
الحزمة الرئيسيةيستورد (
'إف إم تي'
'وقت'
)
مهمة func ( ) {
fmt.Println ( 'تم تنفيذ المهمة في:' ، الوقت الآن ( ) )
}
func الرئيسي ( ) {
تأخير := 3 * الوقت.الثانية
الموقت := time.NewTimer ( تأخير )
< -المؤقت.C
مهمة ( )
}
في هذا المثال، نبدأ بإنشاء مؤقت بتأخير قدره ثلاث ثوانٍ باستخدام الدالة time.NewTimer().
ننتظر بعد ذلك انتهاء صلاحية المؤقت باستخدام '<- timer.C' وننفذ المهمة عند تشغيل المهمة.
يمكنك الاطلاع على برنامجنا التعليمي التفصيلي حول مؤقتات Golang.
الجدولة الدورية
يمكننا أيضًا إنشاء جدول مهام دوري في Go باستخدام مجموعة من goroutines والمؤشرات التي تسمح بتشغيل المهمة على فترات زمنية محددة كما هو موضح في المثال التالي:
يستورد (
'إف إم تي'
'وقت'
)
مهمة func ( ) {
fmt.Println ( 'تم تنفيذ المهمة في:' ، الوقت الآن ( ) )
}
func الرئيسي ( ) {
الفاصل := 2 * الوقت.الثانية
شريط := time.NewTicker ( فاصلة )
الذهاب وظيفة ( ) {
ل شريط النطاق.C {
مهمة ( )
}
} ( )
وقت النوم ( 5 * الوقت.الثانية )
توقف ( )
}
من المثال الموضح، نبدأ بإنشاء شريط 'time.Ticker' الذي يقوم بتشغيل مهمة على فترات زمنية منتظمة. نقوم أيضًا بإعداد goroutine للانتظار المستمر لحدث المؤشر وتشغيل المهمة المحددة.
أولوية المهام وإدارة التبعية
عند التعامل مع أولوية المهمة وجدولة المهام على أساس التبعية، فمن الجيد توخي الحذر حيث توجد احتمالية حدوث أخطاء.
ومع ذلك، في Go، يمكننا تنفيذ الجدولة القائمة على الأولوية والتبعية باستخدام هياكل البيانات مثل قوائم الانتظار وقوائم الانتظار ذات الأولوية.
لحسن الحظ، توفر لنا مكتبة Go القياسية حزمة الحاوية/الكومة لإدارة قوائم الانتظار ذات الأولوية.
خذ بعين الاعتبار المثال التالي الذي يوضح كيفية تكوين الجدولة على أساس الأولوية في Go:
الحزمة الرئيسيةيستورد (
'حاوية/كومة'
'إف إم تي'
)
// المهمة المجدولة مع الاسم والأولوية.
يكتب هيكل المهمة {
الاسم السلسلة
الأولوية كثافة العمليات
}
// قائمة انتظار المهام ذات الأولوية.
يكتب قائمة انتظار المهام [ ] مهمة
func ( قائمة انتظار المهام pq ) فقط ( ) كثافة العمليات { يعود فقط ( pq ) }
func ( قائمة انتظار المهام pq ) أقل ( أنا، ي كثافة العمليات ) منطقي { يعود pq [ أنا ] .أولوية > pq [ ي ] .أولوية } // الأولوية العليا أولا
func ( قائمة انتظار المهام pq ) تبديل ( أنا، ي كثافة العمليات ) { pq [ أنا ] ، ص [ ي ] = pq [ ي ] ، ص [ أنا ] }
func ( pq * قائمة انتظار المهام ) يدفع ( واجهة × { } ) {
البند := س. ( مهمة )
* pq = إلحاق ( * ف، البند )
}
func ( pq * قائمة انتظار المهام ) البوب ( ) واجهه المستخدم { } {
قديم := * pq
ن:= فقط ( قديم )
العنصر:= قديم [ ن- 1 ]
* pq = قديم [ 0 : ن- 1 ]
يعود غرض
}
func الرئيسي ( ) {
المهام := قائمة انتظار المهام {
{ اسم: 'المهمة أ' ، أولوية: 3 } ,
{ اسم: 'المهمة ب' ، أولوية: 1 } ,
{ اسم: 'المهمة ج' ، أولوية: 2 } ,
}
heap.Init ( & مهام )
ل المهام. لين ( ) > 0 {
المهمة := heap.Pop ( & مهام ) . ( مهمة )
fmt.Printf ( 'تنفيذ %s (الأولوية: %d) \ن ' ، اسم المهمة، المهمة.الأولوية )
}
}
في المثال الموضح، نبدأ بتحديد بنية 'المهمة' التي تحتوي على حقول الاسم والأولوية.
نحدد أيضًا 'TaskQueue' كقائمة انتظار ذات أولوية. ننتقل بعد ذلك إلى دفع المهام إلى قائمة الانتظار جنبًا إلى جنب مع الأولويات المقابلة لها.
وأخيرًا، نستخدم حزمة الحاوية/الكومة لإدارة أولويات المهمة. وهذا يسمح للمهام بالعمل حسب مستوى أولوياتها.
خاتمة
في هذا البرنامج التعليمي، قدمنا لك أحد أقوى الجوانب وأكثرها فائدة في تطوير جدولة المهام. لقد تناولنا كيفية العمل مع أساسيات التزامن القوية في Go مثل goroutines والقنوات لإعداد جدولة المهام.