Sobes.tech
Middle+

Kāpēc nav ieteicams izmantot sinhronizācijas blokus un līdzīgas konstrukcijas, strādājot ar korutīnām?

sobes.tech AI

Atbilde no AI

Izmantojot bloķējošās konstrukcijas, piemēram, synchronized vai lock no standarta bibliotēkas, strādājot ar korutīnām, noved pie resursu neefektīvas izmantošanas un var radīt problēmas.

Galvenie iemesli:

  • Nodaļas bloķēšana: Sinhronizācijas bloki apstādinās nodaļas izpildi, ne tikai korutīnas. Ja sinhronizētā blokā tiek izpildīta Suspending-funkcija, nodaļa tiks bloķēta, kamēr Suspending-funkcija nebeigsies un bloķēšana netiks atbrīvota. Tas var novest pie "badavības" citām korutīnām, kas izmanto to pašu nodaļu.
  • Nesaderība ar Suspending-funkcijām: Korutīnu darba mehānisms (konteksta pārslēgšana, turpinājumi) neņem vērā nodaļu līmeņa bloķējumus. Suspending-funkcijas izpilde sinhronizētā blokā pārkāpj korutīnu bezblokējošo raksturu.
  • Strukturētas konkurences principu pārkāpums: Korutīnas ir ar savu atzīmju un hierarhijas sistēmu. Nodaļu līmeņa bloķējumi ignorē šo sistēmu, sarežģot pareizu atcelšanas apstrādi un dzīves cikla pārvaldību.
  • Dēdlocku risks: Nodaļu bloķējumu un korutīnu konkurences mehānismu kombinācija palielina sarežģītu dēdlocku rašanās iespēju, kas ir grūti diagnosticējamas un novēršamas.

Vietā nodaļu līmeņa bloķējumiem, lai sinhronizētu piekļuvi kopīgiem resursiem korutīnās, jāizmanto specializēti konkurences primitivie no kotlinx.coroutines bibliotēkas:

  • Mutex: Nodrošina savstarpēju izslēgšanu. Korutīna, kas mēģina iegūt aizņemtu mutex, apstāsies (bez nodaļas bloķēšanas) līdz mutex tiks atbrīvots.
  • Semaphore: Ierobežo korutīnu skaitu, kas vienlaikus var piekļūt resursam.
  • Channel: Izmanto datu apmaiņai starp korutīnām.
  • Atomic variables: Vienkāršām atomārām operācijām.

Mutex izmantošanas piemērs:

import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.*

val mutex = Mutex()
var counter = 0

suspend fun incrementCounter() {
    mutex.withLock {
        // Kritiskā sekcija
        counter++
    }
}

fun main() = runBlocking {
    // Korutīnu kopas izveide konkurējošai piekļuvei
    repeat(1000) {
        launch {
            incrementCounter()
        }
    }
    delay(1000) // Laika atstāšana korutīnām
    println("Counter: $counter") // Sagaidāms 1000
}

mutex.withLock ir suspending-funkcija. Ja mutex ir aizņemts, korutīna, kas izsauc withLock, apstāsies un atbrīvos siju citiem uzdevumiem. Kad mutex kļūst pieejams, korutīna atsāks darbu. Tas neblokeē siju, atšķirībā no synchronized.