Ce face sync/atomic.AddInt64
O operație atomică se face „dintr-o bucată”: niciun alt goroutine nu poate vedea o valoare pe jumătate scrisă și nicio adunare nu se pierde. atomic.AddInt64(&n, 1) mărește n cu 1 și returnează valoarea nouă; cu delta negativ scade. Pentru un simplu contor este mai rapidă decât un sync.Mutex.
Regula: dacă o variabilă este modificată atomic, toate citirile și scrierile ei trebuie să fie atomice. Citești cu atomic.LoadInt64(&n) și scrii cu atomic.StoreInt64(&n, v), niciodată direct cu n sau n = v cât timp alte goroutine lucrează cu ea.
Din Go 1.19, tipul atomic.Int64 (cu metodele Add, Load, Store) este varianta recomandată: nu poți uita să folosești operațiile atomice, iar alinierea în memorie este garantată. Există funcții la fel pentru int32, uint32, uint64 și uintptr.
Parametri
| Parametru | Descriere |
|---|---|
addr |
Adresa variabilei (&n). |
delta |
Cât se adună (negativ pentru scădere). |
val |
Valoarea scrisă de StoreInt64. |
Ce returnează
AddInt64: valoarea nouă. LoadInt64: valoarea curentă. StoreInt64: nimic.
Exemple
Exemplul 1: Contor de vizite
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var vizite int64
var wg sync.WaitGroup
for range 200 {
wg.Go(func() {
atomic.AddInt64(&vizite, 1)
})
}
wg.Wait()
fmt.Println("Vizite:", atomic.LoadInt64(&vizite))
fmt.Println("După încă 5:", atomic.AddInt64(&vizite, 5))
fmt.Println("După -10: ", atomic.AddInt64(&vizite, -10))
atomic.StoreInt64(&vizite, 0)
fmt.Println("Resetat: ", atomic.LoadInt64(&vizite))
}
Rezultat
Vizite: 200
După încă 5: 205
După -10: 195
Resetat: 0
Exemplul 2: Octeți descărcați de mai mulți lucrători
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
marimi := []int64{1_048_576, 524_288, 2_097_152, 262_144}
var total int64
var wg sync.WaitGroup
for _, m := range marimi {
wg.Go(func() {
for range 4 { // fiecare fișier vine în 4 bucăți
atomic.AddInt64(&total, m/4)
}
})
}
wg.Wait()
fmt.Printf("Descărcat: %d octeți (%.2f MB)\n", atomic.LoadInt64(&total), float64(atomic.LoadInt64(&total))/1024/1024)
}
Rezultat
Descărcat: 3932160 octeți (3.75 MB)
Greșeli frecvente
- Amesteci accesul atomic cu cel obișnuit:
atomic.AddInt64(&n, 1)într-un goroutine șifmt.Println(n)în altul, în același timp. Citirea directă este o cursă de date; foloseșteLoadInt64. - Pe sisteme pe 32 de biți, un
int64folosit atomic într-o structură trebuie să fie aliniat la 8 octeți, altfel programul se oprește. Tipulatomic.Int64rezolvă singur problema.
Comenzi înrudite
sync/atomic.Int64: Un int64 cu operații atomice ca metode (Add, Load, Store, Swap); varianta recomandată pentru contoare între goroutine.sync/atomic.CompareAndSwapInt64: CompareAndSwapInt64 scrie doar dacă valoarea e cea așteptată; SwapInt64 scrie și returnează valoarea veche.sync.Mutex: Lacăt de excludere reciprocă: doar un goroutine pe rând poate rula codul dintre Lock() și Unlock().