Sobes.tech
Middle+

Kotlin'da korutinlardan foydalanib sinxronizatsiyani qanday amalga oshirish mumkin?

sobes.tech AI

AIdan javob

Kotlin coroutines ichqilashda kotlinx.coroutines kutubxonasidan maxsus primitivalar va ma'lumotlar tuzilmalari yordam beradi.

Asosiy yondashuvlar:

  1. Mutex

    • Kritikal kod bo'limlarini himoya qilish uchun o'zaro chiqarishni ta'minlaydi.
    • Mutexni olishga harakat qilayotgan korutina uni bo'shatilguncha bloklanadi.
    • lock() va unlock() funksiyalariga ega, shuningdek, withLock yanada idiomatika.
    import kotlinx.coroutines.sync.Mutex
    import kotlinx.coroutines.sync.withLock
    import kotlinx.coroutines.*
    
    val mutex = Mutex()
    var counter = 0
    
    suspend fun increment() {
        mutex.withLock {
            counter++
        }
    }
    
    suspend fun main() = coroutineScope {
        repeat(10_000) {
            launch {
                increment()
            }
        }
        println(counter) // Kutilyapti 10000
    }
    
  2. Semaphore

    • Bir vaqtning o'zida kirish mumkin bo'lgan korutinalar sonini yoki ma'lum bir kod blokini bajarish uchun cheklov.
    • Ruxsatlar havuzini boshqaradi.
    • acquire() va release() funksiyalariga ega, shuningdek, withPermit.
    import kotlinx.coroutines.sync.Semaphore
    import kotlinx.coroutines.sync.withPermit
    import kotlinx.coroutines.*
    
    val semaphore = Semaphore(2) // Bir vaqtning o'zida 2 ta korutina ishlashi mumkin
    
    suspend fun doLimitedWork(id: Int) {
        semaphore.withPermit {
            println("Korutina $id ruxsat oldi. Ishlayapti...")
            delay(100) // Ishni taqlid qilish
            println("Korutina $id ruxsatni bo'shatdi.")
        }
    }
    
    suspend fun main() = coroutineScope {
        repeat(5) { i ->
            launch {
                doLimitedWork(i)
            }
        }
    }
    
  3. Atomik operatsiyalar (kotlinx.coroutines.atomic dan)

    • Primitiv turlar va havolalar bo'yicha oqim xavfsiz operatsiyalarni taqdim etadi.
    • Past darajadagi CPU instruktsiyalarini (CAS - Compare-and-Swap) ishlatadi.
    • Oddiy operatsiyalar uchun, aniq blokirovkalar bo'lmagan holda mos keladi.
    import kotlinx.coroutines.atomic.AtomicInt
    import kotlinx.coroutines.*
    
    val atomicCounter = AtomicInt(0)
    
    suspend fun atomicIncrement() {
        atomicCounter.incrementAndGet()
    }
    
    suspend fun main() = coroutineScope {
        repeat(10_000) {
            launch {
                atomicIncrement()
            }
        }
        println(atomicCounter.value) // Kutilyapti 10000
    }
    
  4. Yagona ipliqli dispatcherda umumiy ma'lumotlar tuzilmalari

    • Eng oddiy yondashuv. Kodni ketma-ket bajarilishini ta'minlaydigan yagona ipliqli kontekstda (Dispatchers.Default.limitedParallelism(1) yoki newSingleThreadContext) ishga tushirish, raqobat shartlarini oldini oladi. Bu aniq bir sinxronizatsiya primitive emas, lekin kirishni serializatsiya qilish orqali sinxronizatsiya ta'minlaydi.
    import kotlinx.coroutines.*
    
    val mySingleThreadContext = newSingleThreadContext("SingleThread")
    var sharedData = mutableListOf<Int>()
    
    suspend fun addToSharedData(value: Int) {
        sharedData.add(value) // Bir ipda bajarilayotganligi uchun xavfsiz
    }
    
    suspend fun main() = withContext(mySingleThreadContext) {
        repeat(10_000) {
            launch {
                 addToSharedData(it)
            }
        }
        println(sharedData.size) // Kutilyapti 10000
    }
    
  5. Kanalalar

    • O'zlari to'g'ridan-to'g'ri sinxronizatsiya primitive emas, lekin korutinlar o'rtasida ma'lumotlarni xavfsiz uzatish uchun ishlatilishi mumkin, bu uzatilayotgan ma'lumotlarga kirishni sinxronlashtirish muammolarini bilvosita hal qiladi.
    • Bir korutindan ikkinchisiga ma'lumot oqimini uzatish usulini taqdim etadi.

Yondashuv tanlovi foydalanish holatiga bog'liq. Mutex va Semaphore klassik blokirovka mexanizmlarini taqdim etadi, Atomik operatsiyalar oddiy atomik yangilashlar uchun samarali, va yagona ipli dispatcher, agar umumiy ma'lumotlarga kirish qat'iy ketma-ket bo'lishi kerak bo'lsa, qulay. Kanalalar esa aloqa va muvofiqlashtirish uchun ishlatiladi, to'g'ridan-to'g'ri umumiy resurslarni himoya qilish uchun emas.