Sobes.tech
Middle+

¿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.