Sobes.tech
Middle+

Mi az az atom művelet, milyen típusai vannak, és mikor és hogyan érdemes őket használni?

sobes.tech MI

Válasz az MI-től

Atomáris műveletek olyan memória műveletek, amelyek végrehajtása garantáltan vagy teljesen befejeződik, vagy egyáltalán nem kezdődik el, és nem szakíthatók meg más versengő műveletek által. Ezek oszthatatlanok és hardver szinten biztonságosak.

Go nyelvben a sync/atomic csomag funkciókészletet nyújt az atomáris műveletek végrehajtására:

Funkció Leírás
AddInt32 int32 értékhez atomárisan hozzáad
AddInt64 int64 értékhez atomárisan hozzáad
AddUint32 uint32 értékhez atomárisan hozzáad
AddUint64 uint64 értékhez atomárisan hozzáad
AddUintptr uintptr értékhez atomárisan hozzáad
CompareAndSwapInt32 Atomáris összehasonlítás és csere (CAS) int32-hez
CompareAndSwapInt64 Atomáris összehasonlítás és csere (CAS) int64-hez
CompareAndSwapUint32 Atomáris összehasonlítás és csere (CAS) uint32-hez
CompareAndSwapUint64 Atomáris összehasonlítás és csere (CAS) uint64-hez
CompareAndSwapUintptr Atomáris összehasonlítás és csere (CAS) uintptr-hez
LoadInt32 int32 érték atomáris betöltése
LoadInt64 int64 érték atomáris betöltése
LoadUint32 uint32 érték atomáris betöltése
LoadUint64 uint64 érték atomáris betöltése
LoadUintptr uintptr érték atomáris betöltése
LoadPointer unsafe.Pointer érték atomáris betöltése
StoreInt32 int32 érték atomáris tárolása
StoreInt64 int64 érték atomáris tárolása
StoreUint32 uint32 érték atomáris tárolása
StoreUint64 uint64 érték atomáris tárolása
StoreUintptr uintptr érték atomáris tárolása
StorePointer unsafe.Pointer érték atomáris tárolása
SwapInt32 int32 érték atomáris cseréje
SwapInt64 int64 érték atomáris cseréje
SwapUint32 uint32 érték atomáris cseréje
SwapUint64 uint64 érték atomáris cseréje
SwapUintptr uintptr érték atomáris cseréje
SwapPointer unsafe.Pointer érték atomáris cseréje

Az atomáris műveletek használata leginkább akkor ajánlott, amikor egyszerű, alacsony szintű szinkronizációra van szükség a közös változókhoz, általában számlálókhoz vagy zászlókhoz, mutexek használata nélkül. Ezek minimális overheadet biztosítanak és jobb teljesítményt nyújtanak ilyen szcenáriókban.

Atomáris számláló példája:

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() {
			// Atomárisan növeljük a számlálót
			atomic.AddInt64(&counter, 1)
			wg.Done()
		}()
	}

	wg.Wait()
	// Atomárisan betöltjük a számláló értékét
	fmt.Println("Final Counter:", atomic.LoadInt64(&counter))
}

CompareAndSwap használat példája:

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var value int32 = 10

	// Megpróbálja kicserélni az értéket, ha az jelenleg 10, 20-ra
	swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
	fmt.Println("Swapped:", swapped) // Swapped: true
	fmt.Println("Value:", value)   // Value: 20

	// Megpróbálja kicserélni az értéket, ha az jelenleg 10, 30-ra
	swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
	fmt.Println("Swapped:", swapped) // Swapped: false
	fmt.Println("Value:", value)   // Value: 20
}

Fontos megjegyezni, hogy az atomáris műveletek csak primitív típusokkal működnek (egész számok, pointerek). Komplexebb adatszerkezetekhez vagy blokkoló műveletekhez továbbra is mutexek vagy más szinkronizációs mechanizmusok szükségesek. Túlzott vagy helytelen használatuk nehezen észrevehető hibákhoz vagy teljesítménycsökkenéshez vezethet.