Sobes.tech
Middle+

Wat zijn atomare bewerkingen, welke soorten bestaan er en wanneer en hoe is het het beste om ze te gebruiken?

sobes.tech AI

Antwoord van AI

Atomische operaties zijn geheugenbewerkingen waarvan de uitvoering gegarandeerd of volledig wordt voltooid, of helemaal niet begint, en ze kunnen niet worden onderbroken door andere concurrerende operaties. Ze zijn ondeelbaar en hardware-veilig.

In Go biedt het sync/atomic pakket een reeks functies voor het uitvoeren van atomische operaties:

Functie Beschrijving
AddInt32 Voegt atomair een waarde toe aan int32.
AddInt64 Voegt atomair een waarde toe aan int64.
AddUint32 Voegt atomair een waarde toe aan uint32.
AddUint64 Voegt atomair een waarde toe aan uint64.
AddUintptr Voegt atomair een waarde toe aan uintptr.
CompareAndSwapInt32 Atomair vergelijken en ruilen (CAS) voor int32.
CompareAndSwapInt64 Atomair vergelijken en ruilen (CAS) voor int64.
CompareAndSwapUint32 Atomair vergelijken en ruilen (CAS) voor uint32.
CompareAndSwapUint64 Atomair vergelijken en ruilen (CAS) voor uint64.
CompareAndSwapUintptr Atomair vergelijken en ruilen (CAS) voor uintptr.
LoadInt32 Atomair laden van een int32 waarde.
LoadInt64 Atomair laden van een int64 waarde.
LoadUint32 Atomair laden van een uint32 waarde.
LoadUint64 Atomair laden van een uint64 waarde.
LoadUintptr Atomair laden van een uintptr.
LoadPointer Atomair laden van een unsafe.Pointer.
StoreInt32 Atomair opslaan van een int32.
StoreInt64 Atomair opslaan van een int64.
StoreUint32 Atomair opslaan van een uint32.
StoreUint64 Atomair opslaan van een uint64.
StoreUintptr Atomair opslaan van een uintptr.
StorePointer Atomair opslaan van een unsafe.Pointer.
SwapInt32 Atomair ruilen van een int32.
SwapInt64 Atomair ruilen van een int64.
SwapUint32 Atomair ruilen van een uint32.
SwapUint64 Atomair ruilen van een uint64.
SwapUintptr Atomair ruilen van een uintptr.
SwapPointer Atomair ruilen van een unsafe.Pointer.

Het gebruik van atomische operaties is het meest geschikt voor eenvoudige, laag-niveau synchronisatie van gedeelde variabelen, meestal tellers of vlaggen, zonder gebruik te maken van mutexen. Ze bieden minimale overhead en betere prestaties in dergelijke scenario's.

Voorbeeld van het gebruik van een atomische teller:

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() {
			// Atomair verhogen van de teller
			atomic.AddInt64(&counter, 1)
			wg.Done()
		}()
	}

	wg.Wait()
	// Atomair laden van de tellerwaarde
	fmt.Println("Final Counter:", atomic.LoadInt64(&counter))
}

Voorbeeld van het gebruik van CompareAndSwap:

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var value int32 = 10

	// Poging om de waarde te ruilen als deze gelijk is aan 10, naar 20
	swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
	fmt.Println("Swapped:", swapped) // Swapped: true
	fmt.Println("Value:", value)   // Value: 20

	// Poging om de waarde te ruilen als deze gelijk is aan 10, naar 30
	swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
	fmt.Println("Swapped:", swapped) // Swapped: false
	fmt.Println("Value:", value)   // Value: 20
}

Belangrijk: atomische operaties werken alleen met primitieve types (gehele getallen, pointers). Voor synchronisatie van toegang tot complexere datastructuren of het uitvoeren van blokkerende operaties zijn nog steeds mutexen of andere synchronisatie-mechanismen nodig. Overmatig of verkeerd gebruik van atomische operaties kan leiden tot moeilijk te traceren fouten of verminderde prestaties.