I have implemented atomic.LoadInt64 in a way for what I am expecting it will print value in serial order. But it is printing random value. What’s wrong here?
Since I do not understand atomic in deep so what is the concept I am missing here to implement it correctly?
package main
import (
"fmt"
"sync"
"sync/atomic"
)
var wg sync.WaitGroup
var counter int64
func concurrencyGenerator() {
gs := 1000
wg.Add(gs)
for i := 0; i < gs; i++ {
go func() {
atomic.AddInt64(&counter, 1)
fmt.Println("Value : ", atomic.LoadInt64(&counter))
wg.Done()
}()
}
}
func main() {
concurrencyGenerator()
wg.Wait()
fmt.Println(counter)
}
I mean no offence here, but when it comes to atomics, I have to ask: If you do not have a strong understanding of atomics, why are you using them? If it’s to learn atomics, then disregard my question, but I wanted to make sure there’s not a problem that you have and you think atomics are the solution before understanding how they’re supposed to work. Don’t fall for the ol’ Law of the instrument cognitive bias!
Atomics do not synchronize by themselves. They just ensure that operations execute completely, or in the case of operations that can fail, a failure is as if the operation never happened so you can try again without data inconsistencies.
If you want accesses to the counter to run in sequence, then don’t use concurrency and just use a loop. The whole point of parallelism/concurrency is to have separate executions running at the same time (so task #1 runs the same time as #2 and therefore either could complete in any order).
Even though it’s for C++, I highly recommend Fedor Pikus’ CppCon videos on atomics/lock-free/performance:
Are two separate atomic operations and any amount of time could have passed between these two operations. The call to fmt.Println probably eventually gets to an OS system call to write the output to the terminal (or file, etc.) which could cause the Go runtime to execute the operation on some OS thread several microseconds (and many increments of counter) later.