Ce sunt operațiile atomice, care sunt tipurile lor și când și cum este mai bine să le folosiți?
sobes.tech AI
Răspuns de la AI
Operațiile atomice sunt operații asupra memoriei, ale căror execuție se finalizează garantat fie complet, fie nu începe deloc, și nu pot fi întrerupte de alte operații concurente. Ele sunt indivizibile și sigure la nivel hardware.
În Go, pachetul sync/atomic oferă un set de funcții pentru efectuarea operațiilor atomice:
| Funcție | Descriere |
|---|---|
AddInt32 |
Adaugă valoare în mod atomic la int32. |
AddInt64 |
Adaugă valoare în mod atomic la int64. |
AddUint32 |
Adaugă valoare în mod atomic la uint32. |
AddUint64 |
Adaugă valoare în mod atomic la uint64. |
AddUintptr |
Adaugă valoare în mod atomic la uintptr. |
CompareAndSwapInt32 |
Compară și schimbă în mod atomic (CAS) pentru int32. |
CompareAndSwapInt64 |
Compară și schimbă în mod atomic (CAS) pentru int64. |
CompareAndSwapUint32 |
Compară și schimbă în mod atomic (CAS) pentru uint32. |
CompareAndSwapUint64 |
Compară și schimbă în mod atomic (CAS) pentru uint64. |
CompareAndSwapUintptr |
Compară și schimbă în mod atomic (CAS) pentru uintptr. |
CompareAndSwapPointer |
Compară și schimbă în mod atomic (CAS) pentru unsafe.Pointer. |
LoadInt32 |
Încarcă în mod atomic valoarea int32. |
LoadInt64 |
Încarcă în mod atomic valoarea int64. |
LoadUint32 |
Încarcă în mod atomic valoarea uint32. |
LoadUint64 |
Încarcă în mod atomic valoarea uint64. |
LoadUintptr |
Încarcă în mod atomic valoarea uintptr. |
LoadPointer |
Încarcă în mod atomic valoarea unsafe.Pointer. |
StoreInt32 |
Stochează în mod atomic valoarea int32. |
StoreInt64 |
Stochează în mod atomic valoarea int64. |
StoreUint32 |
Stochează în mod atomic valoarea uint32. |
StoreUint64 |
Stochează în mod atomic valoarea uint64. |
StoreUintptr |
Stochează în mod atomic valoarea uintptr. |
StorePointer |
Stochează în mod atomic valoarea unsafe.Pointer. |
SwapInt32 |
Schimbă în mod atomic valoarea int32. |
SwapInt64 |
Schimbă în mod atomic valoarea int64. |
SwapUint32 |
Schimbă în mod atomic valoarea uint32. |
SwapUint64 |
Schimbă în mod atomic valoarea uint64. |
SwapUintptr |
Schimbă în mod atomic valoarea uintptr. |
SwapPointer |
Schimbă în mod atomic valoarea unsafe.Pointer. |
Utilizarea operațiilor atomice este recomandată în cazurile în care este necesară o sincronizare simplă, de nivel inferior, a accesului la variabile comune, de obicei contoare sau steaguri, fără utilizarea mutexurilor. Ele asigură costuri minime și performanță mai bună în astfel de scenarii.
Exemplu de utilizare a unui contor atomic:
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() {
// Crește în mod atomic contorul
atomic.AddInt64(&counter, 1)
wg.Done()
}()
}
wg.Wait()
// Încarcă în mod atomic valoarea contorului
fmt.Println("Final Counter:", atomic.LoadInt64(&counter))
}
Exemplu de utilizare a CompareAndSwap:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 10
// Încearcă să schimbi valoarea dacă este egală cu 10, în 20
swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
fmt.Println("Swapped:", swapped) // Swapped: true
fmt.Println("Value:", value) // Value: 20
// Încearcă să schimbi valoarea dacă este egală cu 10, în 30
swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
fmt.Println("Swapped:", swapped) // Swapped: false
fmt.Println("Value:", value) // Value: 20
}
Este important de reținut că operațiile atomice funcționează doar cu tipuri primitive (numere întregi, pointeri). Pentru sincronizarea accesului la structuri de date mai complexe sau pentru operații blocante, sunt în continuare necesare mutexuri sau alte mecanisme de sincronizare. Utilizarea excesivă sau incorectă a operațiilor atomice poate duce la erori dificil de detectat sau la scăderea performanței.