golang中的并发

时间:2017-03-26 14:49:13

标签: go concurrency

我对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是否使用内部机制隐式管理对共享变量的访问?

谢谢。

6 个答案:

答案 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

参考文献:

Introducing the Go Race Detector

答案 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并行运行。