Reputation: 313
I have two pieces of code and there are 32 cores on my desktop.
Code A uses 32 threads and does the following thing,
1) write values to some random locations in memory 2) atomically add a value to a global variable.
Code B uses 16 threads to write values to random locations and uses another 16 threads to atomically add a value to a global variable.
I was wondering why code B is faster in terms of how many atomic operation executed per second to the global variable.
Here is code A
var a uint64 = 0
const N = 10 * 1024 * 1024
var data [N]uint64
func main() {
for i := 0; i < 32; i ++ {
go func(id int) {
source := rand.NewSource(int64(id))
local_rand := rand.New(source)
for {
atomic.AddUint64(&a, uint64(1))
data[local_rand.Int31n(N)] = uint64(1)
}
}(i)
}
var b uint64 = 0
for {
c := atomic.LoadUint64(&a)
fmt.Println(c - b)
b = c
time.Sleep(time.Second)
}
}
Here is code B
var a uint64 = 0
const N = 10 * 1024 * 1024
var data [N]uint64
func main() {
for i := 0; i < 16; i ++ {
go func(id int) {
source := rand.NewSource(int64(id))
local_rand := rand.New(source)
for {
data[local_rand.Int31n(N)] = uint64(1)
}
}(i)
}
for i := 0; i < 16; i++ {
go func() {
for {
atomic.AddUint64(&a, uint64(1))
}
}()
}
var b uint64 = 0
for {
c := atomic.LoadUint64(&a)
fmt.Println(c - b)
b = c
time.Sleep(time.Second)
}
}
Upvotes: 0
Views: 399
Reputation: 1221
Atomic operations are expensive. In order to maintain atomicity, you need to ensure mutually exclusive execution for that block of code. Usually this is achieved using instructions like load-linked, store-conditional etc. In your code A, you have 32 atomic operations, but in code B, you only got 16. Less atomic work, reduced execution time!
As an experiment, try changing order of the atomic operations with the memory operation in your code A.( Just do memory first and atomic afterwards). You should see a reduction in execution time.
Upvotes: 1