¿Qué son las operaciones atómicas, qué tipos existen y cuándo y cómo es mejor usarlas?
sobes.tech AI
Respuesta de la IA
Las operaciones atómicas son operaciones sobre la memoria que garantizan que se completan completamente o no comienzan en absoluto, y no pueden ser interrumpidas por otras operaciones concurrentes. Son indivisibles y seguras para hilos a nivel de hardware.
En Go, el paquete sync/atomic proporciona un conjunto de funciones para realizar operaciones atómicas:
| Función | Descripción |
|---|---|
AddInt32 |
Suma de forma atómica un valor a int32. |
AddInt64 |
Suma de forma atómica un valor a int64. |
AddUint32 |
Suma de forma atómica un valor a uint32. |
AddUint64 |
Suma de forma atómica un valor a uint64. |
AddUintptr |
Suma de forma atómica un valor a uintptr. |
CompareAndSwapInt32 |
Compara y cambia (CAS) int32 de forma atómica. |
CompareAndSwapInt64 |
Compara y cambia (CAS) int64 de forma atómica. |
CompareAndSwapUint32 |
Compara y cambia (CAS) uint32. |
CompareAndSwapUint64 |
Compara y cambia (CAS) uint64. |
CompareAndSwapUintptr |
Compara y cambia (CAS) uintptr. |
CompareAndSwapPointer |
Compara y cambia (CAS) unsafe.Pointer. |
LoadInt32 |
Carga de forma atómica el valor de int32. |
LoadInt64 |
Carga de forma atómica el valor de int64. |
LoadUint32 |
Carga de forma atómica el valor de uint32. |
LoadUint64 |
Carga de forma atómica el valor de uint64. |
LoadUintptr |
Carga de forma atómica el valor de uintptr. |
LoadPointer |
Carga de forma atómica el valor de unsafe.Pointer. |
StoreInt32 |
Almacena de forma atómica el valor de int32. |
StoreInt64 |
Almacena de forma atómica el valor de int64. |
StoreUint32 |
Almacena de forma atómica el valor de uint32. |
StoreUint64 |
Almacena de forma atómica el valor de uint64. |
StoreUintptr |
Almacena de forma atómica el valor de uintptr. |
StorePointer |
Almacena de forma atómica el valor de unsafe.Pointer. |
SwapInt32 |
Intercambia de forma atómica los valores de int32. |
SwapInt64 |
Intercambia de forma atómica los valores de int64. |
SwapUint32 |
Intercambia de forma atómica los valores de uint32. |
SwapUint64 |
Intercambia de forma atómica los valores de uint64. |
SwapUintptr |
Intercambia de forma atómica los valores de uintptr. |
SwapPointer |
Intercambia de forma atómica los valores de unsafe.Pointer. |
Es mejor usar operaciones atómicas en casos donde se requiere sincronización simple y de bajo nivel para acceso a variables compartidas, como contadores o banderas, sin usar mutexes. Proporcionan costos mínimos y mejor rendimiento en tales escenarios.
Ejemplo de uso de un contador atómico:
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() {
// Incremento atómico del contador
atomic.AddInt64(&counter, 1)
wg.Done()
}()
}
wg.Wait()
// Carga atómica del valor del contador
fmt.Println("Contador final:", atomic.LoadInt64(&counter))
}
Ejemplo de uso de CompareAndSwap:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 10
// Intento de intercambiar el valor si actualmente es 10, a 20
swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
fmt.Println("Intercambio realizado:", swapped) // true
fmt.Println("Valor:", value) // 20
// Intento de intercambiar el valor si actualmente es 10, a 30
swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
fmt.Println("Intercambio realizado:", swapped) // false
fmt.Println("Valor:", value) // 20
}
Es importante recordar que las operaciones atómicas trabajan con tipos de datos primitivos (enteros, punteros). Para sincronizar acceso a estructuras de datos más complejas o realizar operaciones bloqueantes, aún se requieren mutexes u otros mecanismos de sincronización. El uso excesivo o incorrecto de operaciones atómicas puede llevar a errores difíciles de detectar o a una reducción del rendimiento.