我是Go语言的新手,所以如果我的问题很简单,请原谅。我写了一个非常简单的代码:

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
            }()
      }
    }

count的值应增加循环运行次数的1。考虑以下情况:

循环运行100次-> count的值为100(这是正确的,因为循环运行100次)。

循环运行> 510次->计数值是508或510。即使它是100000,也会发生这种情况。

我正在8核处理器计算机上运行它。

最佳答案

首先:在Go 1.5之前,它运行在单个处理器上,仅使用多个线程来阻止系统调用。除非您通过GOMAXPROCS告诉运行时使用更多处理器。

从Go 1.5开始,将GOMAXPROCS设置为CPUS的数量。参见67

同样,操作*cptr = *cptr + 1也不保证是原子的。如果仔细看,它可以分为3个操作:通过取消对指针的引用来获取旧值,递增值,将值保存到指针地址中。

您获得508/510的事实是由于运行时有些不可思议,因此并未定义为保持这种状态。可以在Go memory model中找到有关并发操作行为的更多信息。
您可能正在为
通常,您尝试执行的操作既不推荐使用任何语言,也不推荐使用“Go”方式进行并发。使用 channel 进行同步的一个很好的示例是以下代码遍历:Share Memory By Communicating(而不是通过共享内存进行通信)

Here is a little example to show you what I mean:使用缓冲区为1的 channel 存储当前编号,在需要时从 channel 中获取它,随意更改它,然后将其放回他人使用。

关于parallel-processing - Goroutine在多核处理器上的表现如何,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20993139/

10-15 03:10