当多个例程访问同一结构体的不同字段时,任何并发性问题



如果我们在不同的go协同例程中访问结构体的互斥字段,是否存在任何并发问题?

我记得在某个地方读到,如果两个并行线程访问同一个对象,它们可能会在cpu的不同核心上运行,这两个核心都有不同的cpu级别缓存和不同的对象副本。(与围棋无关)

下面的代码是否足以实现正确的功能,或者是否需要使用额外的同步机制?

package main
import (
"fmt"
"sync"
)
type structure struct {
x string
y string
}
func main() {
val := structure{}
wg := new(sync.WaitGroup)
wg.Add(2)
go func1(&val, wg)
go func2(&val, wg)
wg.Wait()
fmt.Println(val)
}
func func1(val *structure, wg *sync.WaitGroup) {
val.x = "Test 1"
wg.Done()
}
func func2(val *structure, wg *sync.WaitGroup) {
val.y = "Test 2"
wg.Done()
}

编辑:-对于那些问为什么不通道的人不幸的是,这不是我正在工作的实际代码。两个函数都调用了不同的api,并在一个结构体中获取数据,这些结构体中有一个pragma.DoNotCopy,问protobuf自动生成器为什么他们认为这是一个好主意。所以这些数据不能通过通道发送,否则我必须创建另一个结构来发送数据或要求linter停止抱怨。或者我可以发送一个指向对象的指针,但感觉它也在共享内存。

当至少有一个对共享资源的访问为写时,必须进行同步。

你的代码正在做写访问,是的,但是不同的结构域有不同的内存位置。所以你没有访问共享的变量。

如果您使用竞赛检测器运行程序,例如:go run -race main.go打印警告。

现在在func1中添加fmt.Println(val.y)并再次运行,它将打印:

WARNING: DATA RACE
Write at 0x00c0000c0010 by goroutine 8:
... rest of race warning

在Go中首选的方式是通信内存而不是共享内存。

在实践中,这意味着你应该像我在这篇博文中展示的那样使用Go通道。

https://marcofranssen.nl/concurrency-in-go

如果你真的想要共享内存,你将不得不使用互斥锁。

https://tour.golang.org/concurrency/9

但是,这会导致上下文切换和Go例程同步,从而减慢程序的速度。

使用通道的例子

package main
import (
"fmt"
"time"
)
type structure struct {
x string
y string
}
func main() {
val := structure{}
c := make(chan structure)
go func1(c)
go func2(c)
func(c chan structure) {
for {
select {
case v, ok := <-c:
if !ok {
return
}
if v.x != "" {
fmt.Printf("Received %vn", v)
val.x = v.x
}
if v.y != "" {
fmt.Printf("Received %vn", v)
val.y = v.y
}
if val.x != "" && val.y != "" {
close(c)
}
}
}
}(c)
fmt.Printf("%vn", val)
}
func func1(c chan<- structure) {
time.Sleep(1 * time.Second)
c <- structure{x: "Test 1"}
}
func func2(c chan<- structure) {
c <- structure{y: "Test 2"}
}

相关内容

  • 没有找到相关文章

最新更新