跨 Go 例程的共享内存
Shared memory across go routines
Go 中的以下测试失败:
type A struct {
b bool
}
func TestWG(t *testing.T) {
var wg sync.WaitGroup
a := update(&wg)
wg.Wait()
if !a.b {
t.Errorf("error")
}
}
// Does not work
func update(group *sync.WaitGroup) A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
return a
}
最初我认为这可能是由于 waitGroup.Done()
中没有障碍而发生的,这可能解释了为什么将 update
更改为
// works
func update(group *sync.WaitGroup) A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
time.Sleep(1*time.Second)
return a
}
有效。但是然后将 return 类型更改为 pointer
也可以使它工作
// works
func update(group *sync.WaitGroup) *A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
return &a
}
谁能告诉我这里发生了什么?
您的第一个示例存在数据竞争!
你 return a
需要读取它,并发 goroutine(你刚刚启动)在没有同步的情况下写入它。所以输出是未定义的! go test -race
也证实了这一点。
添加睡眠时,情况相同:数据竞争仍然存在(time.Sleep()
不是 同步工具),所以结果仍然未定义! go test -race
再次确认这一点。
当您将 return 类型更改为指针时,您只是 return 一个指向 a
的指针,它不涉及读取 a
的值,并且启动的 goroutine 不修改指针,只修改指向的值。并且调用者 TestWG()
正确地等待直到它使用等待组完成,所以这里没有数据竞争发生。
Go 中的以下测试失败:
type A struct {
b bool
}
func TestWG(t *testing.T) {
var wg sync.WaitGroup
a := update(&wg)
wg.Wait()
if !a.b {
t.Errorf("error")
}
}
// Does not work
func update(group *sync.WaitGroup) A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
return a
}
最初我认为这可能是由于 waitGroup.Done()
中没有障碍而发生的,这可能解释了为什么将 update
更改为
// works
func update(group *sync.WaitGroup) A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
time.Sleep(1*time.Second)
return a
}
有效。但是然后将 return 类型更改为 pointer
也可以使它工作
// works
func update(group *sync.WaitGroup) *A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
return &a
}
谁能告诉我这里发生了什么?
您的第一个示例存在数据竞争!
你 return a
需要读取它,并发 goroutine(你刚刚启动)在没有同步的情况下写入它。所以输出是未定义的! go test -race
也证实了这一点。
添加睡眠时,情况相同:数据竞争仍然存在(time.Sleep()
不是 同步工具),所以结果仍然未定义! go test -race
再次确认这一点。
当您将 return 类型更改为指针时,您只是 return 一个指向 a
的指针,它不涉及读取 a
的值,并且启动的 goroutine 不修改指针,只修改指向的值。并且调用者 TestWG()
正确地等待直到它使用等待组完成,所以这里没有数据竞争发生。