Reputation: 172
I have a question about concurrency in GoLang. Here is a sample code in GoLang
package main
import(
"fmt"
"time"
)
var m int
func add(i int){
m++
}
func main() {
m = 0
for i:=0;i<100;i++{
go add(i)
}
time.Sleep(time.Millisecond * 1000)
fmt.Println(m)
}
When I execute it I always have the same result 100, even if I execute it several times.
If I do the same code in C (without mutex), sometimes I have different results.
And my question, I would like to know if GoLang implicitly manages access to a shared variable using an internal mechanism ?
Thank you.
Upvotes: 4
Views: 1087
Reputation: 1
Goroutines do not run in parallel. Go work scheduler manages all the goroutines such that all the goroutines are run effectively. Since, goroutines are not running in parallel, the answer would always be 100 for the above program. But, there is one setting GOMAXPROCS which is by default 1, but if you set it any number N > 1, the answer would be different everytime since N goroutines are running in parallel.
Upvotes: 0
Reputation: 911
No, you cant get the same result.
package main
import (
"fmt"
"time"
)
var m int
func add(i int) {
m++
}
func main() {
m = 0
for i := 0; i < 10000; i++ {
go add(i)
}
time.Sleep(time.Millisecond * 1000)
fmt.Println(m)
}
Upvotes: 0
Reputation: 3559
I am getting the same results here, but not if I replace
m++
with
func add(i int) {
for j := 0; j < 100000; j++ {
m++
}
}
In the latter case, I confirmed using scheduler tracing that the Go runtime distributed the work on several processor cores, which explains the discrepancy because, indeed, m
is not protected against race conditions. So why does it not happen in the former case ? Probably because a simple integer increment is too short for the Go scheduler to assign the goroutines to several threads, so they execute in sequence, in the same thread. And why does it happen in C : because you manually distribute the calculations on several threads, so the operating system scheduler may decide to execute them on several processor cores.
Upvotes: 3
Reputation: 166529
No. For example, using your program,
$ go run -race dz00dz.go
==================
WARNING: DATA RACE
Read at 0x000000595200 by goroutine 7:
main.add()
/home/peter/gopath/src/dz00dz.go:11 +0x3d
Previous write at 0x000000595200 by goroutine 6:
main.add()
/home/peter/gopath/src/dz00dz.go:11 +0x59
Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/dz00dz.go:17 +0x76
Goroutine 6 (finished) created at:
main.main()
/home/peter/gopath/src/dz00dz.go:17 +0x76
==================
100
Found 1 data race(s)
exit status 66
References:
Introducing the Go Race Detector
Upvotes: 5
Reputation: 21957
You have a race condition here, try to test your code with:
go test -race
It means that m++
is not thread-safe, try something like this:
var (
m int
mu *sync.RWMutex
)
func add(i int){
mu.Lock()
m++
mu.Unlock()
}
Also I see this code is a bit dirty:
1. Remove m = 0
2. Replace Sleep
with WaitGroup
3. Why do you pass i
but do not use it?
Upvotes: 1