我对GoLang中的并发性有疑问。以下是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)
}
当我执行它时,我总是有相同的结果100,即使我多次执行它。
如果我在C中使用相同的代码(没有互斥锁),有时我会得到不同的结果。
我的问题是,我想知道GoLang是否使用内部机制隐式管理对共享变量的访问?
谢谢。
答案 0 :(得分:4)
没有。例如,使用您的程序
$ 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
参考文献:
答案 1 :(得分:2)
我在这里得到的结果相同,但如果我替换
则不会m++
与
func add(i int) {
for j := 0; j < 100000; j++ {
m++
}
}
在后一种情况下,我确认使用scheduler tracing Go运行时在多个处理器核心上分配工作,这解释了这种差异,因为m
确实没有针对竞争条件的保护。那么为什么在前一种情况下不会发生呢?可能是因为简单的整数增量太短而Go调度程序将goroutine分配给多个线程,所以它们在同一个线程中按顺序执行。为什么会在C中发生:因为您在多个线程上手动分配计算,因此操作系统调度程序可能决定在多个处理器内核上执行它们。
答案 2 :(得分:1)
这里有竞争条件,请尝试使用以下代码测试您的代码:
go test -race
这意味着m++
不是线程安全的,尝试这样的事情:
var (
m int
mu *sync.RWMutex
)
func add(i int){
mu.Lock()
m++
mu.Unlock()
}
另外我看到这段代码有点脏:
1.删除m = 0
2.将Sleep
替换为WaitGroup
3.为什么通过i
但不使用它?
答案 3 :(得分:0)
不,你不能得到相同的结果。
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)
}
答案 4 :(得分:0)
// This sample program demonstrates how to create goroutines and
// how the goroutine scheduler behaves with three logical processors.
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
// Allocate three logical processors for the scheduler to use.
runtime.GOMAXPROCS(3)
// processTest is used to wait for the program to finish.
var processTest sync.WaitGroup
// Add a count of three, one for each goroutine.
processTest.Add(3)
// Declaration of three anonymous function and create a goroutine.
go func() {
defer processTest.Done()
for i := 0; i < 30; i++ {
for j := 51; j <= 100; j++ {
fmt.Printf(" %d", j)
if j == 100{
fmt.Println()
}
}
}
}()
go func() {
defer processTest.Done()
for j := 0; j < 10; j++ {
for char := 'A'; char < 'A'+26; char++ {
fmt.Printf("%c ", char)
if char == 'Z' {
fmt.Println()
}
}
}
}()
go func() {
defer processTest.Done()
for i := 0; i < 30; i++ {
for j := 0; j <= 50; j++ {
fmt.Printf(" %d", j)
if j == 50 {
fmt.Println()
}
}
}
}()
// Wait for the goroutines to finish.
processTest.Wait()
}
如果我们给调度程序使用多个逻辑处理器,我们将在示例程序的输出中看到不同的行为。如果运行该程序,您将看到goroutines并行运行。多个goroutine开始运行,显示中的字母和数字混合在一起。输出基于在八核机器上运行程序,因此每个goroutine都在自己的核心上运行。 http://www.golangprograms.com/this-sample-program-demonstrates-how-to-create-multiple-goroutines-and-how-the-goroutine-scheduler-behaves-with-three-logical-processors.html
答案 5 :(得分:0)
Goroutine不能并行运行。 Go Work Scheduler管理所有goroutine,以便有效运行所有goroutine。由于goroutine不是并行运行的,因此上述程序的答案始终为100。但是,只有一个设置GOMAXPROCS,默认情况下为1,但是如果将其设置为N> 1,则每次都会有不同的答案,因为N个goroutine并行运行。