Sobes.tech
Middle+

Ինչպես կարելի է իրականացնել սինխրոնիզացիան Kotlin- ում՝ օգտագործելով կորուտիններ?

sobes.tech AI

Պատասխան AI-ից

Կոնկուրսիաների սինխրոնիզացիան Kotlin- ի կորգինների մեջ հասնում է հատուկ primitive-ների և տվյալների կառուցվածքների միջոցով 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-ից)

    • Առաջարկում է հոսքազուրկ գործողություններ՝ primitives և հղումների վրա։
    • Օգտագործում է ցածր մակարդակի 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. Ընթերցող-գրող տվյալների կառուցվածքներ մեկ-թերթային dispatcher-ով

    • Ամենահեշտ մոտեցումը։ Կորգինների գործարկումը մեկ-թերթային կոնտեքստում (Dispatchers.Default.limitedParallelism(1) կամ newSingleThreadContext) ապահովում է հերթական կատարման։
    • Չի հանդիսանում բացահայտ սինխրոնիզացիայի primitive, բայց ապահովում է սինխրոնիզացիա՝ մուտքի սերիալիզացիայով։
    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. Channels

    • Չեն հանդիսանում սինխրոնիզացիայի primitives, բայց կարող են օգտագործվել տվյալների անվտանգ փոխանցման համար կորգինների միջև, ինչը անուղղակիորեն լուծում է մուտքի սինխրոնիզացիայի խնդիրները։
    • Առաջարկում են տվյալների հոսքի փոխանցում մեկ կորգինից մյուսին։

Ընտրությունը կախված է օգտագործման սցենարից։ Mutex և Semaphore տրամադրում են դասական բլոկավորման մեխանիզմներ, Atomic-ները արդյունավետ են պարզ ատոմարային թարմացումների համար, իսկ մեկ-թերթային dispatcher- ը հարմար է, երբ ընդհանուր տվյալների մուտքը պետք է լինի խիստ հերթական։ Channels- ը օգտագործվում է հաղորդակցման և համակարգման համար, ոչ թե ուղղակիորեն ընդհանուր ռեսուրսների պաշտպանության համար։