How goroutines behave on a multi-core processor

I am new to Go, so please excuse me if my question is very simple. I wrote a very simple code:

func main(){ var count int // Default 0 cptr := &count go incr(cptr) time.Sleep(100) fmt.Println(*cptr) } // Increments the value of count through pointer var func incr(cptr *int) { for i := 0; i < 1000; i++ { go func() { fmt.Println(*cptr) *cptr = *cptr + 1 }() } } 

The counter value should be increased by one by the number of cycle cycles. Consider the cases:

The loop executes 100 times -> the count value is 100 (which is true, since the loop executes 100 times).

The cycle runs for> 510 times β†’ The count value is either 508 OR 510. This happens even if it is 100000.

I run this on an 8-core processor.

+8
parallel-processing go goroutine
source share
4 answers

First of all: before Go 1.5, it runs on a single processor, using only a few threads to block system calls. If you do not tell at run time to use more processors using GOMAXPROCS .

As of Go 1.5, GOMAXPROCS is set to CPUS. See 6 , 7 .

In addition, the operation *cptr = *cptr + 1 not guaranteed to be atomic. If you look carefully, it can be divided into 3 operations: get the old value using the dereference pointer, increment value, save the value to the pointer address.

The fact that you get 508/510 is due to some magic at runtime and is not defined to stay that way. More information on the behavior of concurrency operations can be found in the Go memory model .
You are probably getting the correct values ​​for <510 running goroutines, because any number below this is not interrupted (for now) interrupted.

As a rule, what you are trying to do is not recommended in any language or in the "Go" method to make concurrency. A very good example of using channels for synchronization is a code walk: Share Memory By Communicating (instead of messaging through memory)

Here is a small example to show you what I mean : use the channel with buffer 1 to store the current number, select it from the channel when you need it, change it as you like, then return it for use by others.

+8
source share

You use code: you write in the same memory location from different unsynchronized goroutines without any blockage. The result is mostly undefined. You must either a) make sure that all goroutine are recorded one after another in a beautiful, orderly way, or b) protect each record, for example, e mutex or c) use atomic operations.

If you write code like this: always try it under a race detector like $ go run -race main.go and fix all races.

+9
source share

A good alternative to using channels in this case is the sync / atomic package, which contains special functions for atomically increasing / decreasing numbers.

+1
source share

It all came up to me, noobie here . But I found a better way http://play.golang.org/p/OcMsuUpv2g

I use the sync package to solve this problem and wait until all the goroutines are gone, without sleep or channel.

And don't forget to take a look at this wonderful post http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/

-one
source share

All Articles