Kas yra atomarinės operacijos, kokie jų tipai ir kada ir kaip geriausia jas naudoti?
sobes.tech AI
Atsakymas iš AI
Atomarinės operacijos yra operacijos su atmintimi, kurių vykdymas garantuojamai užbaigiamas arba visiškai, arba visai nepradedamas, ir jos negali būti nutrauktos kitų konkuruojančių operacijų. Jos yra nepadalomos ir saugios keliuose srautuose aparatinės įrangos lygiu.
Go paketas sync/atomic teikia funkcijų rinkinį atomarinių operacijų vykdymui:
| Funkcija | Aprašymas |
|---|---|
AddInt32 |
Atomariškai prideda reikšmę prie int32. |
AddInt64 |
Atomariškai prideda reikšmę prie int64. |
AddUint32 |
Atomariškai prideda reikšmę prie uint32. |
AddUint64 |
Atomariškai prideda reikšmę prie uint64. |
AddUintptr |
Atomariškai prideda reikšmę prie uintptr. |
CompareAndSwapInt32 |
Atomariškai lygina ir keičia (CAS) int32. |
CompareAndSwapInt64 |
Atomariškai lygina ir keičia (CAS) int64. |
CompareAndSwapUint32 |
Atomariškai lygina ir keičia (CAS) uint32. |
CompareAndSwapUint64 |
Atomariškai lygina ir keičia (CAS) uint64. |
CompareAndSwapUintptr |
Atomariškai lygina ir keičia (CAS) uintptr. |
CompareAndSwapPointer |
Atomariškai lygina ir keičia (CAS) unsafe.Pointer. |
LoadInt32 |
Atomariškai įkelia reikšmę int32. |
LoadInt64 |
Atomariškai įkelia reikšmę int64. |
LoadUint32 |
Atomariškai įkelia reikšmę uint32. |
LoadUint64 |
Atomariškai įkelia reikšmę uint64. |
LoadUintptr |
Atomariškai įkelia reikšmę uintptr. |
LoadPointer |
Atomariškai įkelia reikšmę unsafe.Pointer. |
StoreInt32 |
Atomariškai išsaugo reikšmę int32. |
StoreInt64 |
Atomariškai išsaugo reikšmę int64. |
StoreUint32 |
Atomariškai išsaugo reikšmę uint32. |
StoreUint64 |
Atomariškai išsaugo reikšmę uint64. |
StoreUintptr |
Atomariškai išsaugo reikšmę uintptr. |
StorePointer |
Atomariškai išsaugo reikšmę unsafe.Pointer. |
SwapInt32 |
Atomariškai keičia reikšmes int32. |
SwapInt64 |
Atomariškai keičia reikšmes int64. |
SwapUint32 |
Atomariškai keičia reikšmes uint32. |
SwapUint64 |
Atomariškai keičia reikšmes uint64. |
SwapUintptr |
Atomariškai keičia reikšmes uintptr. |
SwapPointer |
Atomariškai keičia reikšmes unsafe.Pointer. |
Naudoti atomarines operacijas yra geriausia tada, kai reikia paprastos, žemo lygio prieigos prie bendrų kintamųjų sinchronizacijos, dažniausiai skaitiklių ar žymeklių, be naudotojų užrakto. Jos užtikrina minimalias išlaidas ir geresnį našumą nei užraktai tokiose scenarijuose.
Pavyzdys naudojant atomarinį skaitiklį:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
// Atomariškai padidiname skaitiklį
atomic.AddInt64(&counter, 1)
wg.Done()
}()
}
wg.Wait()
// Atomariškai įkelia reikšmę skaitiklio
fmt.Println("Galutinis skaitiklis:", atomic.LoadInt64(&counter))
}
Pavyzdys naudojant CompareAndSwap:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 10
// Bandymas pakeisti reikšmę, jei dabartinė yra 10, į 20
swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
fmt.Println("Pakeista:", swapped) // Pakeista: true
fmt.Println("Reikšmė:", value) // Reikšmė: 20
// Bandymas pakeisti reikšmę, jei dabartinė yra 10, į 30
swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
fmt.Println("Pakeista:", swapped) // Pakeista: false
fmt.Println("Reikšmė:", value) // Reikšmė: 20
}
Svarbu prisiminti, kad atomarinės operacijos veikia su primityviais duomenų tipais (visas skaičius, nuorodos). Daugiau sudėtingų duomenų struktūrų ar blokuojančių operacijų sinchronizacijai vis dar reikalingi užraktai ar kiti sinchronizacijos mechanizmai. Pernelyg didelis ar netinkamas atomarinių operacijų naudojimas gali sukelti sunkiai aptinkamas klaidas arba sumažinti našumą.