Sobes.tech
Middle+

Чӣ гуна метавон ҳамоҳангсозиро дар Kotlin бо истифода аз корутинҳо амалӣ кард?

sobes.tech AI

Ҷавоб аз AI

Сінхранізацыя ў Kotlin корутінах дасягаецца з дапамогай спецыяльных прымітываў і структур дадзеных з бібліятэкі kotlinx.coroutines.

Асноўныя падыходы:

  1. Mutex

    • Забяспечвае ўзаемнае выключэнне для абароны крытычных секцый кода.
    • Корутына, якая спрабуе атрымаць Mutex, блакуецца, пакуль ён не будзе вызвалены.
    • Мае функцыі lock() і unlock(), а таксама больш ідыёматычны withLock.
    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) // Чакаем 10000
    }
    
  2. Semaphore

    • Абмяжоўвае колькасць корутин, якія могуць адначасова атрымаць доступ да рэсурсу або выканаць пэўны блок кода.
    • Кіруе пулом дазволаў.
    • Мае функцыі acquire() і release(), а таксама withPermit.
    import kotlinx.coroutines.sync.Semaphore
    import kotlinx.coroutines.sync.withPermit
    import kotlinx.coroutines.*
    
    val semaphore = Semaphore(2) // Адначасова могуць працаваць 2 корутины
    
    suspend fun doLimitedWork(id: Int) {
        semaphore.withPermit {
            println("Корутына $id атрымала дазвол. Працуе...")
            delay(100) // Імітацыя працы
            println("Корутына $id вызваліла дазвол.")
        }
    }
    
    suspend fun main() = coroutineScope {
        repeat(5) { i ->
            launch {
                doLimitedWork(i)
            }
        }
    }
    
  3. Атамарныя аперацыі (з kotlinx.coroutines.atomic)

    • Забяспечваюць патокабяспечныя аперацыі над праімтыўнымі тыпамі і спасылкамі.
    • Выкарыстоўваюць нізка ўзроўневыя інструкцыі CPU (CAS - Compare-and-Swap).
    • Падыходзяць для простых аперацый без відавочных блакіровак.
    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) // Чакаем 10000
    }
    
  4. Дзеляныя структуры дадзеных на дыспетчары з адным патокам

    • Самы просты падыход. Запуск корутин на аднапотокавым кантэксце (Dispatchers.Default.limitedParallelism(1) або newSingleThreadContext) гарантуе паслядоўнае выкананне кода, выключаючы гонкі дадзеных. Не з'яўляецца відавочным прымітывам сінхранізацыі, але забяспечвае сінхранізацыю шляхам серыялізацыі доступу.
    import kotlinx.coroutines.*
    
    val mySingleThreadContext = newSingleThreadContext("SingleThread")
    var sharedData = mutableListOf<Int>()
    
    suspend fun addToSharedData(value: Int) {
        sharedData.add(value) // Бяспечна, бо выконваецца на адным патоку
    }
    
    suspend fun main() = withContext(mySingleThreadContext) {
        repeat(10_000) {
            launch {
                 addToSharedData(it)
            }
        }
        println(sharedData.size) // Чакаем 10000
    }
    
  5. Каналы

    • Не з'яўляюцца прымітывамі сінхранізацыі ў чыстым выглядзе, але могуць выкарыстоўвацца для бяспечнай перадачы дадзеных паміж коруцінамі, што косвена вырашае праблемы сінхранізацыі доступу да перадаваемых дадзеных.
    • Забяспечваюць спосаб перадачы патоку дадзеных з адной корутины ў іншую.

Выбар падыходу залежыць ад сцэнарыя выкарыстання. Mutex і Semaphore прапануюць класічныя механізмы блакіроўкі, атомарныя аперацыі эфектыўныя для простых атомарных абнаўленняў, а дыспетчар з адным патокам зручны, калі доступ да агульных дадзеных павінен быць строга паслядоўным. Каналы выкарыстоўваюцца для камунікацыі і каардынацыі, а не для прамой абароны агульных рэсурсаў.