التزامن

📄 الأصل: concurrency.naftah

📦 تحميل الملف: ⬇ تحميل

🔗 عرض الملف:

	
		--- SPDX-License-Identifier: Apache-2.0
--- Copyright © The Naftah Project Authors

---*
هذا الملف يحتوي على مجموعة من التعليمات بلغة برمجة نفطه، ويهدف إلى توضيح مكوّنات وآليات
التنفيذ المتزامن (Concurrency) والمتوازي (Parallelism) في اللغة، وذلك من خلال أمثلة
عملية تغطي عدداً كبيراً من المفاهيم الأساسية والمتقدمة، من بينها:

• تشغيل المهام غير المتزامنة (Asynchronous Tasks) باستخدام:
  - تشغيل (async run)
  - انتظار (await)
  - المهام الطويلة طويلة المدى

• العمل ضمن نطاقات (Scopes) متداخلة والتحكم في دورة حياة المتغيرات
  وتأثير النطاق على النتائج عند التعامل مع القوائم والمجموعات.

• استخدام دوال الحزم والمكتبات للتعامل مع البنى التكرارية مثل:
  - الحصول على عنصر من قائمة أو مجموعة
  - تعديل عنصر داخل بنية متعددة العناصر

• إنشاء قنوات (Channels) لإرسال واستقبال الرسائل بين العمليات المتوازية،
  وهو ما يمكّن من بناء أنظمة تواصل متزامنة بين المكونات.

• تعريف الممثلين (Actors) بطرق مختلفة:
  - ممثل بسيط يستقبل رسالة ويطبعها
  - ممثل يحتوي خصائص داخلية (الاسم، عداد الرسائل)
  - ممثل يزداد ذكاءً مع كل رسالة يستقبلها

• تنفيذ نمط المنتج–المستهلك (Producer/Consumer Pattern):
  - المنتج يرسل رسائل متتابعة عبر القناة
  - المستهلك يستقبل الرسائل ويمررها إلى ممثل لمعالجتها

• التحكم في ترتيب التنفيذ من خلال:
  - نطاق
  - نطاق مرتب
  مما يسمح بتحديد ما إذا كانت المهام يجب أن تُشغّل بالتوازي أو بالتسلسل.

تُظهر الأمثلة الواردة في هذا الملف قوة نموذج التزامن في لغة نفطه،
وقدرتها على بناء مهام متوازية، أنظمة مراسلة، ومعالجات متعددة،
بطريقة واضحة وقابلة للتحكم، مع الحفاظ على بساطة صياغة اللغة.
*---


---*
هذا القسم يوضح كيفية استخدام دوال الحزم للتعامل مع:
  - الحصول على عنصر من قائمة أو مجموعة
  - تعديل عنصر داخل بنية بيانات
  - تشغيل وظائف بشكل غير متزامن
  - استخدام "نطاق" لإنشاء بيئة متغيرة محليًا
 مع الحفاظ على كل التكرارات كما في السكربت الأصلي.
*---

--- تشغيل مهمة غير متزامنة للحصول على عنصر من قائمة
--- إطلاق مهمة
ثابت شغل تعيين تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
--- انتظار انتهاء المهمة
انتظار شغل

--- بداية نطاق مستقل
نطاق {
--- إنشاء قائمة جديدة داخل النطاق
متغير قائمة_ تعيين [1 , 2 , 3]
--- تعديل العنصر رقم 1 إلى 99
دوال:الحزم::تعيين_عنصر(قائمة_, 1 , 99)
--- طباعة/تشغيل القائمة بعد التعديل
تشغيل قائمة_

--- إنشاء مجموعة جديدة
متغير مجموعة_ تعيين {1 , 2}
--- تعديل العنصر الثاني في المجموعة
دوال:الحزم::تعيين_عنصر(مجموعة_, 1 , 99)
--- طباعة المجموعة
تشغيل مجموعة_

--- تشغيل دالة الحصول على عنصر من قائمة مؤقتة
تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
--- الحصول على عنصر من تركيبة (Tuple)
دوال:الحزم::حصول_على_عنصر((1 , 2), 1)
--- الحصول على عنصر من مجموعة
تشغيل دوال:الحزم::حصول_على_عنصر({1 , 2}, 1)

--- نطاق متداخل (بدأ التكرار 1)
نطاق {
متغير قائمة_ تعيين [1 , 2 , 3]
دوال:الحزم::تعيين_عنصر(قائمة_, 1 , 99)
تشغيل قائمة_

متغير مجموعة_ تعيين {1 , 2}
دوال:الحزم::تعيين_عنصر(مجموعة_, 1 , 99)
تشغيل مجموعة_

تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
دوال:الحزم::حصول_على_عنصر((1 , 2), 1)
تشغيل دوال:الحزم::حصول_على_عنصر({1 , 2}, 1)

--- نطاق متداخل (بدأ التكرار 2)
نطاق {
متغير قائمة_ تعيين [1 , 2 , 3]
دوال:الحزم::تعيين_عنصر(قائمة_, 1 , 99)
تشغيل قائمة_

متغير مجموعة_ تعيين {1 , 2}
دوال:الحزم::تعيين_عنصر(مجموعة_, 1 , 99)
تشغيل مجموعة_

تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
دوال:الحزم::حصول_على_عنصر((1 , 2), 1)
تشغيل دوال:الحزم::حصول_على_عنصر({1 , 2}, 1)

--- نطاق متداخل (بدأ التكرار 3)
نطاق {
متغير قائمة_ تعيين [1 , 2 , 3]
دوال:الحزم::تعيين_عنصر(قائمة_, 1 , 99)
تشغيل قائمة_

متغير مجموعة_ تعيين {1 , 2}
دوال:الحزم::تعيين_عنصر(مجموعة_, 1 , 99)
تشغيل مجموعة_

تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
دوال:الحزم::حصول_على_عنصر((1 , 2), 1)
تشغيل دوال:الحزم::حصول_على_عنصر({1 , 2}, 1)

--- نطاق متداخل (بدأ التكرار 4)
نطاق {
متغير قائمة_ تعيين [1 , 2 , 3]
دوال:الحزم::تعيين_عنصر(قائمة_, 1 , 99)
تشغيل قائمة_

متغير مجموعة_ تعيين {1 , 2}
دوال:الحزم::تعيين_عنصر(مجموعة_, 1 , 99)
تشغيل مجموعة_

تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
دوال:الحزم::حصول_على_عنصر((1 , 2), 1)
تشغيل دوال:الحزم::حصول_على_عنصر({1 , 2}, 1)

--- نطاق متداخل (بدأ التكرار 5)
نطاق {
متغير قائمة_ تعيين [1 , 2 , 3]
دوال:الحزم::تعيين_عنصر(قائمة_, 1 , 99)
تشغيل قائمة_

متغير مجموعة_ تعيين {1 , 2}
دوال:الحزم::تعيين_عنصر(مجموعة_, 1 , 99)
تشغيل مجموعة_

تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1)
دوال:الحزم::حصول_على_عنصر((1 , 2), 1)
تشغيل دوال:الحزم::حصول_على_عنصر({1 , 2}, 1)
}
}
}
}
}
}

---*
هذا القسم يوضّح كيفية إنشاء دالة غير متزامنة (async)
 وتنفيذ عمليات طويلة باستخدام انتظار (await).
 بالإضافة إلى تشغيل المهمات، انتظار نتائجها، وتركيب نتائج مع عمليات أخرى.
*---

--- تعريف دالة غير متزامنة تقوم بعملية طويلة
غير_متزامن دالة مهمة_طويلة_المدى(ثابت بادئة : تسلسل_أحرف ،ثابت نهاية_الحلقة_التكرارية = 100000) {
--- تحضير قائمة لتجميع النتائج
ثابت قائمة_النتائج تعيين []

--- حلقة طويلة حسب العدد المطلوب
كرر_حلقة أ تعيين 0 إلى نهاية_الحلقة_التكرارية إفعل {
--- تجهيز النص الناتج
ثابت نتيجة = "{{بادئة}}-{{أ}}"
--- طباعة النتيجة أثناء التنفيذ
إطبع(نتيجة)
--- تخزين النتيجة داخل القائمة
قائمة_النتائج::إضافة(أ؛نتيجة)
}
أنهي

--- إرجاع كل النتائج عند انتهاء المهمة
ارجع قائمة_النتائج
}

--- انتظار تنفيذ مهمة طويلة (تشغيل ثم انتظار)
--- تنفيذ الدالة ثم انتظار نتائجها
انتظار مهمة_طويلة_المدى("مهمة")

--- محاولة تشغيل دالة غير متزامنة (مثال غير صالح)
ثابت شغل تعيين تشغيل مهمة_طويلة_المدى("مهمة")

--- أمثلة صحيحة لتشغيل مهمة طويلة
--- تشغيل المهمة وإرجاع كائن المهمة
ثابت شغل تعيين مهمة_طويلة_المدى("مهمة")
--- تشغيل المهمة بعدد 10 دورات فقط
ثابت شغل تعيين مهمة_طويلة_المدى("مهمة"؛10)
--- انتظار انتهاء الشغل
انتظار شغل

--- مثال على دمج انتظار (await) مع عملية أخرى
--- ضرب نتيجة غير متزامنة (async) في نتيجة غير متزامنة (async) أخرى
ثابت نتيجة_شغل تعيين انتظار مهمة_طويلة_المدى("مهمة"؛10) * (انتظار تشغيل دوال:الحزم::حصول_على_عنصر([1 , 2 , 3], 1))
--- ضرب نتيجة المهمة بقيمة ثابتة
ثابت نتيجة_شغل تعيين انتظار مهمة_طويلة_المدى("مهمة"؛10) * 10
--- طباعة النتيجة
نتيجة_شغل

---*
 تنفيذ عدة مهام طويلة داخل نطاقات مختلفة
*---
نطاق {
 مهمة_طويلة_المدى("مهمة-1"؛2)
 مهمة_طويلة_المدى("مهمة-2"؛10)
 مهمة_طويلة_المدى("مهمة-3"؛15)
 مهمة_طويلة_المدى("مهمة-4"؛150)
 مهمة_طويلة_المدى("مهمة-5"؛50)
 مهمة_طويلة_المدى("مهمة-6"؛500)
 مهمة_طويلة_المدى("مهمة-7"؛11)
 مهمة_طويلة_المدى("مهمة-8"؛5)
 مهمة_طويلة_المدى("مهمة-9"؛100)
 مهمة_طويلة_المدى("مهمة-10"؛1000)
}

---*
 تنفيذ نفس المهام داخل نطاق مرتب
 أي أن التنفيذ يتم بترتيب محدد أو دفعات مرتبة (الأول بالأول)
*---
نطاق مرتب {
 مهمة_طويلة_المدى("مهمة-1"؛2)
 مهمة_طويلة_المدى("مهمة-2"؛10)
 مهمة_طويلة_المدى("مهمة-3"؛15)
 مهمة_طويلة_المدى("مهمة-4"؛150)
 مهمة_طويلة_المدى("مهمة-5"؛50)
 مهمة_طويلة_المدى("مهمة-6"؛500)
 مهمة_طويلة_المدى("مهمة-7"؛11)
 مهمة_طويلة_المدى("مهمة-8"؛5)
 مهمة_طويلة_المدى("مهمة-9"؛100)
 مهمة_طويلة_المدى("مهمة-10"؛1000)
}

---*
 مجموعة مختلفة من المهام الطويلة بأعداد أصغر للتنفيذ
*---
نطاق {
 مهمة_طويلة_المدى("مهمة-1"؛2)
 مهمة_طويلة_المدى("مهمة-2"؛2)
 مهمة_طويلة_المدى("مهمة-3"؛2)
 مهمة_طويلة_المدى("مهمة-4"؛5)
 مهمة_طويلة_المدى("مهمة-5"؛3)
 مهمة_طويلة_المدى("مهمة-6"؛6)
 مهمة_طويلة_المدى("مهمة-7"؛2)
 مهمة_طويلة_المدى("مهمة-8"؛3)
 مهمة_طويلة_المدى("مهمة-9"؛10)
 مهمة_طويلة_المدى("مهمة-10"؛4)
}

---*
 نفس المجموعة ولكن داخل نطاق مرتب
*---
 نطاق مرتب {
 مهمة_طويلة_المدى("مهمة-1"؛2)
 مهمة_طويلة_المدى("مهمة-2"؛2)
 مهمة_طويلة_المدى("مهمة-3"؛2)
 مهمة_طويلة_المدى("مهمة-4"؛5)
 مهمة_طويلة_المدى("مهمة-5"؛3)
 مهمة_طويلة_المدى("مهمة-6"؛6)
 مهمة_طويلة_المدى("مهمة-7"؛2)
 مهمة_طويلة_المدى("مهمة-8"؛3)
 مهمة_طويلة_المدى("مهمة-9"؛10)
 مهمة_طويلة_المدى("مهمة-10"؛4)
}

---*
 هذا القسم يوضّح مكونات النمط المتزامن (Concurrency):
 1) القنوات (Channels): تُستخدم لإرسال/استقبال الرسائل بين المهام.
 2) الممثلون (Actors): كائنات تتلقى رسائل وتنفذ وظائف عند استقبالها.
 3) المنتج (Producer): يرسل بيانات إلى القناة.
 4) المستهلك (Consumer): يستقبل البيانات من القناة ويمررها للممثل.
 هذا مثال كامل يشرح النظام بالكامل.
*---

--- إنشاء قناة مشتركة لنقل الرسائل بين المنتج والمستهلك
قناة قناة_مشتركة

--- ممثل بسيط يقوم فقط بطباعة الرسائل المستلمة
ممثل طابعة(رسالة_الطابعة){
إطبع(رسالة_الطابعة) --- طباعة الرسالة مباشرة
}

--- ممثل آخر باسم طابعة و اسم متغير الرسالة الأصلي "رسالة_الممثل"
ممثل طابعة {
إطبع(رسالة_الممثل)  --- يطبع رسالة بإستعمال اسم متغير الرسالة الأصلي
}

--- ممثل بطابعة مع بيانات أولية
ممثل طابعة(رسالة_الطابعة, --- اسم متغير الرسالة
(
متغير الاسم تعيين "طابعة" --- خاصية: اسم الممثل
)
){
إطبع("{{الاسم}} : {{رسالة_الطابعة}}") --- طباعة مع تضمين الاسم والرسالة
}

--- ممثل بطابعة يحتوي حقولًا إضافية ويعدّ عدد الرسائل
ممثل طابعة(
(
متغير الاسم تعيين "طابعة", --- اسم الممثل
متغير عدد_الرسائل تعيين 0 --- عداد الرسائل
)
){
عدد_الرسائل++  --- زيادة عدّاد المستلم
إطبع("اسم الممثل: {{الاسم}} - رسالة عدد: {{عدد_الرسائل}} - الرسالة: {{رسالة_الممثل}}") --- طباعة مفصلة للرسالة
}

--- دالة غير متزامنة تقوم بإرسال عدد كبير من الرسائل عبر القناة
غير_متزامن دالة منتج(ثابت قناة_ ، ثابت نهاية_الحلقة_التكرارية = 100000) {
 --- حلقة إرسال الرسائل
كرر_حلقة أ تعيين 0 إلى نهاية_الحلقة_التكرارية إفعل {
   قناة_::إرسال("منتج أرسل رسالة عدد {{أ}}") --- إرسال رسالة عبر القناة
}
أنهي
}

--- المستهلك يستقبل رسالة من القناة ويعطيها للممثل لمعالجتها
دالة مستهلك(ثابت قناة_ ، ثابت طابعة ، ثابت نهاية_الحلقة_التكرارية = 100000) {
كرر_حلقة أ تعيين 0 إلى نهاية_الحلقة_التكرارية إفعل {
    ثابت رسالة = قناة_::الاستلام() --- استقبال رسالة من القناة
    طابعة::إرسال(رسالة) --- إرسال الرسالة إلى الممثل لمعالجتها
}
أنهي
}

--- تشغيل المنتج والمستهلك معًا
نطاق {
 منتج(قناة_مشتركة؛10)  --- تشغيل المنتج وإرسال 10 رسائل
 تشغيل مستهلك(قناة_مشتركة؛طابعة؛10) --- تشغيل المستهلك بشكل متزامن لمعالجة 10 رسائل
}