التزامن وتعدد الخيوط في Kotlin: المستوى المتقدم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

التزامن وتعدد الخيوط في Kotlin: المستوى المتقدم

\n

في التطوير الحديث باستخدام Kotlin، خاصة لتطبيقات الخادم (Server) وتطبيقات Android، فإن الإدارة الجيدة للتزامن هي مفتاح الأداء والاستجابة. على المستوى المتقدم، لا يكفي مجرد تشغيل coroutine. بل يجب فهم كيفية مزامنة الوصول إلى البيانات بكفاءة، وإدارة الخيوط، وتجنب "الجحيم" من الأقفال. في هذه المقالة، سنشرح التقنيات المتقدمة: من تفاصيل kotlinx.coroutines إلى المجموعات الآمنة للخيوط والقنوات.

\n\n

1. الغوص العميق في coroutines: التزامن المنظم (Structured Concurrency) والنطاقات (Scopes)

\n

أساس العمل المتقدم هو التزامن المنظم (Structured Concurrency). وهو مبدأ يتم فيه ربط دورة حياة coroutine بنطاق الرؤية (scope). إذا تم إلغاء coroutine الأصلي، يتم إنهاء جميع المهام التابعة له تلقائيًا. هذا يمنع تسرب الذاكرة والعمليات غير المنضبطة.

\n

على المستوى المتقدم، يجب عليك إنشاء نطاقات خاصة بك، بدلاً من الاعتماد على النطاق العام GlobalScope.

\n\n
import kotlinx.coroutines.*\nimport kotlin.coroutines.CoroutineContext\n\nclass DataRepository {\n    // نطاق خاص مع موزع ومعالج استثناءات\n    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler { _, throwable ->\n        println("خطأ غير معالج: ${throwable.message}")\n    })\n\n    fun loadData() {\n        scope.launch {\n            // coroutines تابعة\n            val data = async { fetchFromNetwork() }\n            val cache = async { loadFromCache() }\n            process(data.await(), cache.await())\n        }\n    }\n\n    fun cleanup() {\n        scope.cancel() // إلغاء جميع coroutines في النطاق\n    }\n}
\n\n

استخدم SupervisorJob عندما لا يجب أن يؤدي فشل coroutine تابع إلى إلغاء البقية. هذا أمر بالغ الأهمية لطبقات واجهة المستخدم (UI) أو الطلبات المستقلة المتوازية.

\n\n

2. المجموعات الآمنة للخيوط (Thread-Safe Collections) والعمليات الذرية (Atomic Operations)

\n

حتى مع coroutines، إذا كنت تعمل مع بيانات قابلة للتغيير ومشتركة، فأنت بحاجة إلى المزامنة. يقدم Kotlin عدة طرق:

\n
    \n
  • الأنواع الذرية (AtomicInteger, AtomicReference) — للعدادات والأعلام البسيطة.
  • \n
  • المجموعات الآمنة للخيوط (ConcurrentHashMap, CopyOnWriteArrayList) — للهياكل المعقدة.
  • \n
  • Mutex من kotlinx.coroutines — للأقسام الحرجة داخل coroutines.
  • \n
\n\n
import kotlinx.coroutines.*\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass SafeCounter {\n    private val mutex = Mutex()\n    private var counter = 0\n\n    suspend fun increment() {\n        mutex.withLock {\n            counter++ // قسم حرج\n        }\n    }\n\n    fun getCounter(): Int = counter\n}\n\nclass CacheManager {\n    private val cache = ConcurrentHashMap<String, String>()\n    private val hitCount = AtomicInteger(0)\n\n    fun put(key: String, value: String) {\n        cache[key] = value\n    }\n\n    fun get(key: String): String? {\n        val result = cache[key]\n        if (result != null) hitCount.incrementAndGet()\n        return result\n    }\n}
\n\n

هام: Mutex هي دالة تعليق (suspend function)، لذا فهي لا تحجب الخيط، بل تعلق coroutine. هذا أكثر كفاءة من synchronized.

\n\n

3. القنوات (Channels) و Flow: تدفقات البيانات التفاعلية

\n

لنقل البيانات بين coroutines، استخدم Channels (مشابه لـ BlockingQueue لـ coroutines) و Flow (تدفق غير متزامن بارد).

\n\n

القنوات: منتج-مستهلك (Producer-Consumer)

\n
import kotlinx.coroutines.channels.*\nimport kotlinx.coroutines.*\n\nfun Corout                

المدونات

توصيات الكتب