Τι είναι οι ατομικές λειτουργίες, ποιοι τύποι υπάρχουν και πότε και πώς είναι καλύτερο να τις χρησιμοποιείτε;
sobes.tech AI
Απάντηση από AI
Ατομικές λειτουργίες είναι λειτουργίες στη μνήμη, η εκτέλεση των οποίων ολοκληρώνεται εγγυημένα είτε πλήρως είτε καθόλου, και δεν μπορούν να διακοπούν από άλλες ανταγωνιστικές λειτουργίες. Είναι αδιαίρετες και ασφαλείς σε επίπεδο υλικού.
Στο Go, το πακέτο sync/atomic παρέχει μια σειρά από συναρτήσεις για την εκτέλεση ατομικών λειτουργιών:
| Συνάρτηση | Περιγραφή |
|---|---|
AddInt32 |
Προσθέτει μια τιμή ατομικά στο int32. |
AddInt64 |
Προσθέτει μια τιμή ατομικά στο int64. |
AddUint32 |
Προσθέτει μια τιμή ατομικά στο uint32. |
AddUint64 |
Προσθέτει μια τιμή ατομικά στο uint64. |
AddUintptr |
Προσθέτει μια τιμή ατομικά στο uintptr. |
CompareAndSwapInt32 |
Συγκρίνει και ανταλλάσσει ατομικά (CAS) για το int32. |
CompareAndSwapInt64 |
Συγκρίνει και ανταλλάσσει ατομικά (CAS) για το int64. |
CompareAndSwapUint32 |
Συγκρίνει και ανταλλάσσει ατομικά (CAS) για το uint32. |
CompareAndSwapUint64 |
Συγκρίνει και ανταλλάσσει ατομικά (CAS) για το uint64. |
CompareAndSwapUintptr |
Συγκρίνει και ανταλλάσσει ατομικά (CAS) για το uintptr. |
CompareAndSwapPointer |
Συγκρίνει και ανταλλάσσει ατομικά (CAS) για το unsafe.Pointer. |
LoadInt32 |
Φορτώνει ατομικά την τιμή int32. |
LoadInt64 |
Φορτώνει ατομικά την τιμή int64. |
LoadUint32 |
Φορτώνει ατομικά την τιμή uint32. |
LoadUint64 |
Φορτώνει ατομικά την τιμή uint64. |
LoadUintptr |
Φορτώνει ατομικά την τιμή uintptr. |
LoadPointer |
Φορτώνει ατομικά την τιμή unsafe.Pointer. |
StoreInt32 |
Αποθηκεύει ατομικά την τιμή int32. |
StoreInt64 |
Αποθηκεύει ατομικά την τιμή int64. |
StoreUint32 |
Αποθηκεύει ατομικά την τιμή uint32. |
StoreUint64 |
Αποθηκεύει ατομικά την τιμή uint64. |
StoreUintptr |
Αποθηκεύει ατομικά την τιμή uintptr. |
StorePointer |
Αποθηκεύει ατομικά την τιμή unsafe.Pointer. |
SwapInt32 |
Ατομικά ανταλλάσσει την τιμή int32. |
SwapInt64 |
Ατομικά ανταλλάσσει την τιμή int64. |
SwapUint32 |
Ατομικά ανταλλάσσει την τιμή uint32. |
SwapUint64 |
Ατομικά ανταλλάσσει την τιμή uint64. |
SwapUintptr |
Ατομικά ανταλλάσσει την τιμή uintptr. |
SwapPointer |
Ατομικά ανταλλάσσει την τιμή unsafe.Pointer. |
Η χρήση ατομικών λειτουργιών είναι η καλύτερη επιλογή σε περιπτώσεις όπου απαιτείται απλός, χαμηλού επιπέδου συγχρονισμός πρόσβασης σε κοινές μεταβλητές, συχνά μετρητές ή σημαίες, χωρίς τη χρήση mutex. Παρέχουν ελάχιστο overhead και καλύτερη απόδοση σε τέτοια σενάρια.
Παράδειγμα χρήσης ατομικού μετρητή:
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() {
// Ατομικά αυξάνουμε τον μετρητή
atomic.AddInt64(&counter, 1)
wg.Done()
}()
}
wg.Wait()
// Ατομικά φορτώνουμε την τιμή του μετρητή
fmt.Println("Final Counter:", atomic.LoadInt64(&counter))
}
Παράδειγμα χρήσης CompareAndSwap:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 10
// Προσπάθεια ανταλλαγής αν η τρέχουσα τιμή είναι 10, σε 20
swapped := atomic.CompareAndSwapInt32(&value, 10, 20)
fmt.Println("Swapped:", swapped) // Swapped: true
fmt.Println("Value:", value) // Value: 20
// Προσπάθεια ανταλλαγής αν η τρέχουσα τιμή είναι 10, σε 30
swapped = atomic.CompareAndSwapInt32(&value, 10, 30)
fmt.Println("Swapped:", swapped) // Swapped: false
fmt.Println("Value:", value) // Value: 20
}
Σημαντικό: οι ατομικές λειτουργίες λειτουργούν μόνο με primitive τύπους δεδομένων (ακέραιοι, δείκτες). Για συγχρονισμό πρόσβασης σε πιο πολύπλοκες δομές δεδομένων ή εκτέλεση μπλοκαριστικών λειτουργιών, απαιτούνται mutex ή άλλα μηχανισμοί συγχρονισμού. Η υπερβολική ή λανθασμένη χρήση ατομικών λειτουργιών μπορεί να οδηγήσει σε δυσδιάκριτα σφάλματα ή μείωση της απόδοσης.