go 中可通过以下方法安全获取 goroutine 的共享数据:1. 互斥锁(mutex):允许一个 goroutine 独占访问共享数据;2. 通道(channel):协调对共享数据的访问,并作为 goroutine 间的数据传递机制;3. 原子操作(atomic operation):原子性地读取和修改共享变量,保证数据的一致性。
如何安全地获取 Go 中 goroutine 中的共享数据?
在并发编程中,协调对共享数据的访问至关重要。Go 语言提供了多种方法来实现这一点,其中包括互斥锁、通道和原子操作。
互斥锁
互斥锁(Mutex)用于一次允许一个 goroutine 访问共享数据。要创建一个互斥锁,可以使用 sync.Mutex 类型。以下是如何使用互斥锁示例:
package main
import (
"fmt"
"sync"
)
// 共享变量
var counter int
func main() {
var mu sync.Mutex
// 创建 10 个 goroutine,每个 goroutine 增加 counter
for i := 0; i < 10; i++ {
go func() {
mu.Lock()
defer mu.Unlock()
counter++
fmt.Printf("goroutine %d: %dn", i, counter)
}()
}
}
通道
通道可以用来在 goroutine 之间传递数据,也可以用来协调对共享数据的访问。要创建通道,可以使用 make(chan) 函数。以下是如何使用通道示例:
package main
import (
"fmt"
"sync"
)
// 共享变量
var counter int
func main() {
ch := make(chan struct{})
// 创建 10 个 goroutine,每个 goroutine 增加 counter
for i := 0; i < 10; i++ {
go func() {
defer close(ch)
for {
select {
case <-ch:
return
default:
counter++
fmt.Printf("goroutine %d: %dn", i, counter)
}
}
}()
}
// 等待所有 goroutine 完成
for i := 0; i < 10; i++ {
<-ch
}
}
原子操作
原子操作可以用来原子性地读取和修改共享变量的值。Go 语言提供了 sync/atomic 包,用于支持原子操作。以下是如何使用原子操作示例:
package main
import (
"fmt"
"sync/atomic"
)
// 共享变量
var counter int
func main() {
// 使用 AddInt64 增加 counter
for i := 0; i < 10; i++ {
go func() {
atomic.AddInt64(&counter, 1)
fmt.Printf("goroutine %d: %dn", i, counter)
}()
}
}
在这些方法中,选择哪种方法取决于具体场景和所需的安全保证级别。