Sobes.tech
Middle+

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.