Sobes.tech
Middle+

როგორ შეიძლება Kotlin- ში სინქრონიზაცია განხორციელდეს კორუტინების გამოყენებით?

sobes.tech AI

პასუხი AI-სგან

კოტლინ კორუტინებში სინქრონიზაცია აღწევს სპეციალური 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. გაერთიანებული მონაცემთა სტრუქტურები ერთ-თრედის დისპეტჩერით

    • ყველაზე მარტივი მიდგომა. 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)

    • არ არის სინქრონიზაციის primitive, მაგრამ შეიძლება გამოყენებულ იქნას მონაცემების უსაფრთხო გადაცემისთვის კორუტინებს შორის, რაც ირიბად აგვარებს მონაცემთა წვდომის პრობლემებს.
    • მონაცემთა ნაკადის გადაცემის საშუალებაა ერთი კორუტინიდან მეორე კორუტინამდე.

მოდელი დამოკიდებულია გამოყენების სცენარზე. Mutex და Semaphore უზრუნველყოფენ კლასიკურ ბლოკირების მექანიზმებს, Atomic ოპერაციები ეფექტურია მარტივი ატომური განახლებებისთვის, ხოლო ერთ-თრედის დისპეტჩერი სასარგებლოა, როდესაც საერთო მონაცემების წვდომა უნდა იყოს მკაცრად სერიული. Channels გამოიყენება კომუნიკაციის და კოორდინაციისთვის, არა პირდაპირი საერთო რესურსების დაცვისთვის.