البنائين الـ Builders

Mohammad Laifمنذ 4 سنوات

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته

 

 في هذا الدرس سنتعرف على البنائين مايعرف بالـ Builders, والذي من خلالهم نبني الكروتينات. فبعد أن تعرفنا في الدرس السابق على النطاق Scope والتي تكمن وظيفته في تحديد المكان الذي سننشئ فيه الكروتينات. حان الوقت لبناء الكروتين في ذلك النطاق بإستخدام احد البنائين. فالبناء اولاً يجب عليه أن يعرف النطاق الذي سيبنى فيه الكروتين.


ماذا ستقرئ في هذا الدرس

  • ما هو البناء Builder.
  • أنواع البنائين.
    • النوع الأول الـ runBlocking.
    • النوع الثاني الـ launch.
    • النوع الثالث الـ async.
      • مثال برمجي لإرجاع عنصر من نوع Deferred يحمل نتيجة.
      • مثال برمجي لتشغيل شفرتان في شكل متنافس Concurrent.
    • النوع الرابع withContext.
  • متى تستخدم هذه الأنواع.

 

ما هو البناء Builder

هو عبارة عن دوال يوفرها API Coroutines في لغة الكوتلن نقوم باستخدامهم لبناء الكروتين.

 

أنواع البنائين

 

النوع الأول الـ runBlocking

هذا النوع يقوم بحجب الخيط الحاسوبي الذي يعمل عليه الكروتين لغاية اتمام العمل, وهذا شئ غير جيد. فنحن لا نريد حجب الخيط الحاسوبي. مايميزه انه لايحتاج الى نطاق, فهو يصنع نطاقه بنفسه. أغلب أستخداماته في حالات كتابة الاختبارات.

مثال برمجي:

fun main() {
    runBlocking {
        println("Hello World")
    }
}
  • لاحظ لاحاجة للـ runBlocking بوجود نطاق Scope, لانه يملك واحد ضمني implicit خاص به.

 

النوع الثاني الـ launch

أما هذا النوع لا يقوم بحجب الخيط الحاسوبي. ويقوم بإرجاع عنصر من نوع Job. وبالعادة ستكثر من إستخدام هذا النوع.

مثال برمجي:

GlobalScope.launch(Dispatchers.Default) {
    println("Hello World from Coroutine")
}

// Or
val myJob: Job = GlobalScope.launch(Dispatchers.Default) {
    println("Hi from Coroutine 2")
}
  • لاحظ ان هذا النوع يتطلب نطاق Scope, وهنا هو Globalscope.
  • نستطيع اسناد له عنصر من نوع Job للتحكم به.

 

النوع الثالث الـ async

هذا النوع لا يقوم بحجب الخيط الحاسوبي, ولكنه يستطيع حجب الكروتين نفسه وذلك بإستخدام الدالة await(). وهكذا يستطيع الانتظار لإرجاع عنصر من نوع Deferred وما هو إلا عنصر Job يحمل في طياته نتيجة ما. كذلك نفهم من اسمه انه يستطيع تشغيل عدت شفرات برمجية في شكل موازي.

بالنسبة لنوع الـ Deferred فهو عبارة عن كائن مستقبلي الـ future قابل للإلغاء. للتعرف على الكائن المستقبل, تفضل بقراءة مقالة المشغل و المنادى والكائنات المستقبلية في الاندرويد و درس مكونات الخيوط الحاسوبية (Thread).

يعتبر من اهم البنائين, من خلاله تستطيع ارجاع قيمة, وكذلك تستطيع تشغيل اكثر من شفرة في شكل تنافسي Concurrent (متزامن, شبه متوازي) . يكثر استخدامة مع الدوال التأجيلية كما سنرى في الدروس القادمة.

 

مثال برمجي لإرجاع عنصر من نوع Deferred يحمل نتيجة:

val myDeferred: Deferred<Int> = GlobalScope.async { return@async 1 }

 

مثال برمجي لتشغيل شفرتان في شكل متنافس Concurrent:

fun main() {
    val totalTime: Long = measureTimeMillis {
        runBlocking {
            val functionATime: Deferred<Long> = async { functionA() }
            val functionBTime: Deferred<Long> = async { functionB() }
            println("functionA: ${functionATime.await()} functionB: ${functionBTime.await()}")
        }
    }
    println("Total Time $totalTime")
}


suspend fun functionA(): Long = measureTimeMillis {
    delay(4000)
}

suspend fun functionB(): Long = measureTimeMillis {
    delay(4000)
}
  • لاحظ احتياج البناء async لإن يكون من ضمن اب إي يتم مناداته واستخدامة من داخل كروتينه, هنا استخدمنا البناء runblocking لصنع كروتينه وندائه.
  • لاحظ طريقة استخدام عنصر الـ Deferred وذلك بوجوب نداء الدالة await() والتي تحجب هذه الكروتينه الاب الى حين انتهاء العمل.
  • لاحظ الدالتين A و B من نوع الدوال التأجيلية سنتعرف عليهم في درس مختص بهم. المهم هو كل دالة منهما تتطلب ٤ ثواني للإتمام.
  • لاحظ ان النتيجة ستكون فقط ٤ ثواني بدلاً من ٨ ثواني.

 

النتيجة:

functionA: 4002 functionB: 4000
Total Time 4015

 

سنتعرف اكثر على هذا البناء async وعلى الدوال التأجيلية بشكل مفصل في درس مختص بها. مايهم هنا هو طريقة استخدام البناء async.

 

 

النوع الرابع withContext

هذا البناء او بالاحرى هذه الدالة تسمح لنا بتغيير الموزع Dispatcher (جافا: الخيط الحاسوبي) وسنتعرف على انواعه في الدرس القادم.
بإستخدام هذه الدالة نستطيع تغيير الخيط الحاسوبي من الرئيسي الى خيط حاسوبي خلفي لإتمام العمل, ومن ثم الرجوع الى الخيط الرئيسي.

مثال برمجي:

fun main(){
    runBlocking {
        // We are in: Main Thread.
        val result: String = withContext(Dispatchers.IO) {
            // Now we are in: Background Thread.
            "Mohammad"
        }

        // We back again on: Main Thread with the result.
        println(result)
    }
}
  • لاحظ الكروتينة المنشئة بإستخدام البناء runBlocking هي على الخيط الحاسوبي الرئيسي.
  • لاحظ بإستخدام البناء withContext أستطعنا الذهاب لخيط حاسوبي خلفي (يتمثل في Dispatchers.IO).
  • لاحظ الرجوع الى الخيط الحاسوبي الرئيسي لطباعة النتيجة (الوظيفة مشابهه للـ asyncTask).
  • يكثر استخدام هذا البناء مع الدوال التأجيلية وسنتعرف عليهم لاحقاً.

 

متى تستخدم هذه الأنواع

من المهم جداً معرفة متى تستخدم هذه الأنواع فإذا كنت تريد كتابة اختبارات فسيكون النوع runBlocking هو المناسب لك. اما اذا كنت تريد تشغيل شفرة برمجية ما, ولا تريد منها ارجاع اي شئ فأفضل خيار هو launch. ولكن إذا كنت مهتم بإرجاع قيمة فعليك استخدام النوع الثالث async. وكذلك هو مناسب اذا اردت تشغيل عدة شفرات في شكل متوازي.

 

المصادر

المحاضر

Mohammad Laif

محتوى الدورة

الكلمات الدليلية

عن الدرس

0 إعجاب
1 متابع
0 مشاركة
1184 مشاهدات
منذ 4 سنوات

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !