Middle+
Kodėl nerekomenduojama naudoti sinchronizacijos blokus ir panašias konstrukcijas dirbant su korutinomis?
sobes.tech AI
Atsakymas iš AI
Naudojant blokuojančias konstrukcijas, tokias kaip synchronized arba lock iš standartinės bibliotekos, dirbant su korutinomis, tai veda prie neefektyvaus išteklių naudojimo ir gali sukelti problemų.
Pagrindinės priežastys:
- Vėlavimas užrakinti srautą: Sinchronizacijos blokai sustabdo srauto vykdymą, o ne tik korutinų. Jei sinchronizuoto bloko viduje vykdoma Suspending-funkcija, srautas bus užblokuotas, kol Suspending-funkcija nebaigs ir užraktas nebus atlaisvintas. Tai gali sukelti "badavimą" kitų korutinų, naudojančių tą patį srautą.
- Nesuderinamumas su Suspending-funkcijomis: Korutinų darbo mechanizmas (konteksto perjungimas, tęsiniai) neatsižvelgia į srautų lygio užraktus. Suspending-funkcijos vykdymas sinchronizuotame bloke pažeidžia korutinų neblokavimo pobūdį.
- Struktūruotos konkurencijos principų pažeidimas: Korutinų turi savo atšaukimo žymas ir hierarchiją. Srautų lygio užraktai šią sistemą ignoruoja, apsunkindami teisingą atšaukimo apdorojimą ir gyvavimo ciklo valdymą.
- Dėl užrakto užstringimo rizika: Srautų užraktų ir korutinų konkurencijos mechanizmų derinys didina sudėtingų užstringimų tikimybę, kurių diagnozavimas ir taisymas yra sudėtingas.
Vietoj srautų lygio užraktų, siekiant sinchronizuoti prieigą prie bendrų išteklių korutinose, reikėtų naudoti specializuotus konkurencijos primityvus iš kotlinx.coroutines bibliotekos:
Mutex: Užtikrina tarpusavio išskyrimą. Korutina, bandanti užimti užimtas mutex, sustabdo (be srauto blokavimo) iki tol, kol mutex bus atlaisvintas.Semaphore: Ribojia korutinų skaičių, kurios gali vienu metu naudotis ištekliu.Channel: Naudojamas duomenų mainams tarp korutinų.Atomic variables: Paprastoms atominėms operacijoms.
Mutex naudojimo pavyzdys:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.*
val mutex = Mutex()
var counter = 0
suspend fun incrementCounter() {
mutex.withLock {
// Kritinė sekcija
counter++
}
}
fun main() = runBlocking {
// Sukuriame korutinų rinkinį konkurenciniam prieigai
repeat(1000) {
launch {
incrementCounter()
}
}
delay(1000) // Duodame laiko korutinoms įvykdyti
println("Counter: $counter") // Tikimės 1000
}
mutex.withLock yra suspending-funkcija. Jei mutex užimtas, korutina, iškvietusi withLock, sustos ir atlaisvins srautą kitiems užduotims. Kai mutex taps prieinamas, korutina atnaujins darbą. Tai neblokuoja srauto, skirtingai nuo synchronized.