gpt4 book ai didi

go - 使用 WaitGroup 测试竞争条件时的意外行为

转载 作者:IT王子 更新时间:2023-10-29 01:56:35 25 4
gpt4 key购买 nike

我的任务是在 Go 中模拟竞争条件。但是,我遇到了一个我无法解释的案例。下面的代码片段

package main

import (
"fmt"
"sync"
)

var value, totalOps, totalIncOps, totalDecOps int

func main() {
fmt.Println("Total value: ", simulateRacing(10000))
fmt.Print("Total iterations: ", totalOps)
fmt.Print(" of it, increments: ", totalIncOps)
fmt.Print(", decrements: ", totalDecOps)
}

// Function to simulate racing condition
func simulateRacing(iterationsNumber int) int {
value = 0
// Define WaitGroup
var waitGroup sync.WaitGroup
waitGroup.Add(2)

go increaseByOne(iterationsNumber, &waitGroup)
go decreaseByOne(iterationsNumber, &waitGroup)

waitGroup.Wait()

return value
}

// Function to do N iterations, each time increasing value by 1
func increaseByOne(N int, waitGroup *sync.WaitGroup) {
for i := 0; i < N; i++ {
value++
// Collecting stats
totalOps++
totalIncOps++
}
waitGroup.Done()
}

// Same with decrease
func decreaseByOne(N int, waitGroup *sync.WaitGroup) {
for i := 0; i < N; i++ {
value--
// Collecting stats
totalOps++
totalDecOps++
}
waitGroup.Done()
}

根据我的理解,它每次都应该产生一致(确定性)的结果,因为我们进行相同数量的递增和递减,并使用 WaitGroup 确保两个函数都将执行。

但是,每次输出都不同,只有增量和减量计数器保持不变。<我> 总值(value):2113 总迭代次数:17738 次,增量:10000,减量:10000 和<我>总值(value):35总迭代次数:10741 次,增量:10000,减量:10000

也许你能帮我解释一下这种行为?为什么总迭代计数器和值本身是不确定的?

最佳答案

这是竞争条件的经典示例。 value++ 不是原子操作,因此无法保证在没有同步的情况下从多个线程调用时它会正确或确定地工作。

为了直观起见,value++ 或多或少等同于 value = value + 1。您可以将其视为三个 操作,而不是一个:从内存加载 到 CPU 寄存器,增加寄存器中的值(您不能直接修改内存),存储值返回内存。两个线程可能同时加载相同的值,增加它,得到相同的结果,然后将它写回,所以它有效地将 value 增加 1,而不是两个。

由于线程之间的操作顺序是不确定的,因此结果也是不确定的。

同样的效果发生在 totalOps 上。但是,totalIncOpstotalDecOps 只会被单个线程修改/读取,因此这里没有竞争,它们的最终值是确定的。

关于go - 使用 WaitGroup 测试竞争条件时的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53790644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com