مقدمة في التزامن وتعدد الخيوط في Kotlin
تتطلب التطبيقات الحديثة بشكل متزايد تنفيذ مهام متعددة في وقت واحد - من معالجة طلبات الشبكة إلى العمل مع قواعد البيانات. في لغة Kotlin، التي تُستخدم بنشاط لتطوير تطبيقات Android، وتطبيقات الخادم (Ktor, Spring)، وحتى تطبيقات سطح المكتب، تم تنفيذ أدوات قوية للعمل مع التزامن وتعدد الخيوط.
في هذه المقالة، سنقوم بتحليل المفاهيم الأساسية: الخيوط التقليدية (Threads)، الكوروتينات (Coroutines) - النهج الحديث للبرمجة غير المتزامنة في Kotlin، بالإضافة إلى آليات المزامنة. ستتعرف على متى يجب استخدام الخيوط، ومتى تستخدم الكوروتينات، وستحصل على أمثلة جاهزة للكود.
1. الخيوط التقليدية (Threads) في Kotlin
Kotlin متوافق تمامًا مع Java، لذا يمكنك استخدام الفئات القياسية Thread و Runnable. ومع ذلك، يضيف Kotlin سكرًا نحويًا يجعل الكود أكثر إيجازًا.
إنشاء وتشغيل خيط
الطريقة الأساسية لإنشاء خيط هي تمرير لامدا إلى مُنشئ Thread:
fun main() { val thread = Thread { println("الخيط قيد التشغيل: ${Thread.currentThread().name}") for (i in 1..5) { println("العد: $i") Thread.sleep(500) } } thread.start() println("الخيط الرئيسي يواصل العمل") thread.join() // انتظار انتهاء الخيط println("الخيط الرئيسي انتهى")}في هذا المثال، أنشأنا خيطًا يقوم بطباعة الأرقام من 1 إلى 5 مع تأخير قدره 500 مللي ثانية. الطريقة join() تجبر الخيط الرئيسي على انتظار انتهاء الخيط الفرعي.
مشاكل الخيوط
- استهلاك عالي للموارد - يتطلب كل خيط مساحة ذاكرة مكدس منفصلة (عادةً 1 ميجابايت).
- تعقيد المزامنة - عند العمل مع بيانات مشتركة، من السهل حدوث حالة سباق (race condition).
- عدد محدود - لا يمكن تشغيل عشرات الآلاف من الخيوط على جهاز واحد دون فقدان الأداء.
لهذا السبب ظهرت الكوروتينات في Kotlin - كبديل أخف وزنًا.
2. الكوروتينات (Coroutines) - التزامن الحديث في Kotlin
الكوروتينات هي خيوط خفيفة الوزن يمكنها تعليق تنفيذها دون حظر خيط النظام. وهي الأداة الرئيسية للبرمجة غير المتزامنة في Kotlin.
إضافة الكوروتينات
للعمل مع الكوروتينات، يجب إضافة التبعية في ملف build.gradle.kts:
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")}مثال أساسي لكوروتين
import kotlinx.coroutines.*
fun main() = runBlocking { println("بدء العمل في الخيط: ${Thread.currentThread().name}")
launch { // تشغيل كوروتين جديد delay(1000) // تأخير غير محظور println("الكوروتين: ${Thread.currentThread().name}") }
println("الكوروتين الرئيسي يواصل العمل") delay(2000) // انتظار انتهاء الكوروتين الفرعي println("النهاية")}النقاط الرئيسية:
runBlocking- جسر بين الكود العادي والكوروتينات (يحظر الخيط الحالي).launch- يبدأ كوروتينًا لا يُرجع نتيجة.delay- تأخير غير محظور، على عكسThread.sleep().
Async و await للحصول على النتيجة
إذا كان يجب على الكوروتين إرجاع قيمة، استخدم async:
fun main() = runBlocking { val deferred1 = async { delay(1000) "النتيجة 1" } val deferred2 = async { delay(500) "النتيجة 2" }
println("انتظار النتائج...") val result1 = deferred1.await() val result2
```