Sobes.tech
Middle+

Kas ir atomu operācijas, kādi ir to veidi un kad un kā labāk tās izmantot?

sobes.tech AI

Atbilde no AI

Atomārās operācijas ir operācijas ar atmiņu, kuru izpilde tiek garantēti vai nu pilnībā, vai vispār nesākas, un tās nevar pārtraukt citas konkurējošas operācijas. Tās ir nedalāmas un aparatūras līmenī drošas.

Go pakotne sync/atomic nodrošina funkciju kopumu atomāru operāciju veikšanai:

Funkcija Apraksts
AddInt32 Atomāri pievieno vērtību int32.
AddInt64 Atomāri pievieno vērtību int64.
AddUint32 Atomāri pievieno vērtību uint32.
AddUint64 Atomāri pievieno vērtību uint64.
AddUintptr Atomāri pievieno vērtību uintptr.
CompareAndSwapInt32 Atomāri salīdzina un apmaina (CAS) int32.
CompareAndSwapInt64 Atomāri salīdzina un apmaina (CAS) int64.
CompareAndSwapUint32 Atomāri salīdzina un apmaina (CAS) uint32.
CompareAndSwapUint64 Atomāri salīdzina un apmaina (CAS) uint64.
CompareAndSwapUintptr Atomāri salīdzina un apmaina (CAS) uintptr.
CompareAndSwapPointer Atomāri salīdzina un apmaina (CAS) unsafe.Pointer.
LoadInt32 Atomāri ielādē vērtību int32.
LoadInt64 Atomāri ielādē vērtību int64.
LoadUint32 Atomāri ielādē vērtību uint32.
LoadUint64 Atomāri ielādē vērtību uint64.
LoadUintptr Atomāri ielādē vērtību uintptr.
LoadPointer Atomāri ielādē vērtību unsafe.Pointer.
StoreInt32 Atomāri saglabā vērtību int32.
StoreInt64 Atomāri saglabā vērtību int64.
StoreUint32 Atomāri saglabā vērtību uint32.
StoreUint64 Atomāri saglabā vērtību uint64.
StoreUintptr Atomāri saglabā vērtību uintptr.
StorePointer Atomāri saglabā vērtību unsafe.Pointer.
SwapInt32 Atomāri apmaina vērtības int32.
SwapInt64 Atomāri apmaina vērtības int64.
SwapUint32 Atomāri apmaina vērtības uint32.
SwapUint64 Atomāri apmaina vērtības uint64.
SwapUintptr Atomāri apmaina vērtības uintptr.
SwapPointer Atomāri apmaina vērtības unsafe.Pointer.

Atomāru operāciju izmantošana ir vislabākā gadījumos, kad nepieciešama vienkārša, zema līmeņa piekļuve kopīgajiem mainīgajiem, bieži skaitītājiem vai zīmjiem, bez slēdžiem. Tās nodrošina minimālas izmaksas un labāku veiktspēju salīdzinājumā ar slēdžiem šādos scenārijos.

Piemērs ar atomāru skaitītāju:

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āri palielinām skaitītāju
			atomic.AddInt64(&counter, 1)
			wg.Done()
		}()
	}

	wg.Wait()
	// Atomāri ielādē skaitītāja vērtību
	fmt.Println("Galīgais skaitītājs:", atomic.LoadInt64(&counter))
}

Piemērs ar CompareAndSwap:

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var value int32 = 10

	// Mēģinājums apmainīt vērtību, ja tā ir 10, uz 20
	swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
	fmt.Println("Mainīts:", swapped) // Mainīts: true
	fmt.Println("Vērtība:", value)   // Vērtība: 20

	// Mēģinājums apmainīt vērtību, ja tā ir 10, uz 30
	swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
	fmt.Println("Mainīts:", swapped) // Mainīts: false
	fmt.Println("Vērtība:", value)   // Vērtība: 20
}

Svarīgi atcerēties, ka atomāras operācijas darbojas ar primītiem datu tipiem (veseliem skaitļiem, norādēm). Lai sinhronizētu piekļuvi uz sarežģītākām datu struktūrām vai veiktu bloķējošas operācijas, joprojām ir nepieciešami slēdži vai citi sinhronizācijas mehānismi. Pārmērīga vai nepareiza atomāru operāciju izmantošana var novest pie grūti uztveramu kļūdu vai veiktspējas samazināšanās.