跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
Go 内存同步
”︁(章节)
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= Go内存同步 = '''内存同步'''是Go语言并发编程中的核心概念,指多个goroutine在访问共享内存时如何保证数据的一致性和正确性。Go通过内置的同步原语(如互斥锁、通道等)来协调并发访问,避免竞态条件(race conditions)和数据竞争(data races)。 == 基本概念 == 在并发程序中,当多个goroutine同时读写同一块内存时,如果没有适当的同步机制,程序的执行结果可能变得不可预测。Go的内存同步机制确保: * '''可见性''':一个goroutine对共享变量的修改能够被其他goroutine及时看到。 * '''有序性''':操作执行的顺序符合程序逻辑的预期。 === 竞态条件示例 === 以下代码展示了一个典型的竞态条件: <syntaxhighlight lang="go"> package main import ( "fmt" "sync" ) var counter int func increment(wg *sync.WaitGroup) { defer wg.Done() counter++ } func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println("Final counter:", counter) // 结果可能小于1000 } </syntaxhighlight> '''输出可能为''': <pre> Final counter: 987 # 每次运行结果可能不同 </pre> == 同步机制 == Go提供了多种内存同步机制,主要分为两类: === 1. 互斥锁(Mutex) === 通过<code>sync.Mutex</code>实现对共享资源的独占访问: <syntaxhighlight lang="go"> package main import ( "fmt" "sync" ) var ( counter int mu sync.Mutex ) func increment(wg *sync.WaitGroup) { defer wg.Done() mu.Lock() counter++ mu.Unlock() } func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println("Final counter:", counter) // 保证输出1000 } </syntaxhighlight> '''输出''': <pre> Final counter: 1000 </pre> === 2. 通道(Channel) === 通过通道实现goroutine间的通信和同步: <syntaxhighlight lang="go"> package main import ( "fmt" "sync" ) func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) { defer wg.Done() for j := range jobs { results <- j * 2 } } func main() { jobs := make(chan int, 100) results := make(chan int, 100) var wg sync.WaitGroup // 启动3个worker for w := 1; w <= 3; w++ { wg.Add(1) go worker(w, jobs, results, &wg) } // 发送任务 for j := 1; j <= 5; j++ { jobs <- j } close(jobs) // 接收结果 go func() { wg.Wait() close(results) }() // 打印结果 for r := range results { fmt.Println("Result:", r) } } </syntaxhighlight> '''输出''': <pre> Result: 2 Result: 4 Result: 6 Result: 8 Result: 10 </pre> == 内存模型 == Go的内存模型定义了goroutine操作共享变量的可见性规则。关键概念包括: * '''happens-before'''关系:如果事件A happens-before事件B,那么A对内存的修改在B执行时是可见的。 * '''同步原语''':以下操作会建立happens-before关系: * 通道的发送操作happens-before对应的接收操作完成 * <code>sync.Mutex</code>或<code>sync.RWMutex</code>的解锁操作happens-before后续的加锁操作 === 内存模型示例 === <mermaid> sequenceDiagram participant Goroutine1 participant Goroutine2 Goroutine1->>Goroutine2: 通道发送数据 Goroutine2->>Goroutine1: 通道接收完成(建立happens-before) </mermaid> == 高级主题 == === 原子操作 === 对于简单的计数器,可以使用<code>sync/atomic</code>包: <syntaxhighlight lang="go"> package main import ( "fmt" "sync" "sync/atomic" ) var counter int64 func increment(wg *sync.WaitGroup) { defer wg.Done() atomic.AddInt64(&counter, 1) } func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println("Final counter:", counter) // 保证输出1000 } </syntaxhighlight> === 内存屏障 === Go编译器可能会对指令进行重排序,内存屏障确保特定操作不会被重排序: <math> \text{Load} \rightarrow \text{Barrier} \rightarrow \text{Store} </math> == 实际应用案例 == '''场景''':实现一个线程安全的缓存 <syntaxhighlight lang="go"> package main import ( "fmt" "sync" ) type Cache struct { mu sync.RWMutex items map[string]string } func NewCache() *Cache { return &Cache{ items: make(map[string]string), } } func (c *Cache) Set(key, value string) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = value } func (c *Cache) Get(key string) (string, bool) { c.mu.RLock() defer c.mu.RUnlock() val, ok := c.items[key] return val, ok } func main() { cache := NewCache() cache.Set("name", "Alice") if val, ok := cache.Get("name"); ok { fmt.Println("Got:", val) // 输出: Got: Alice } } </syntaxhighlight> == 最佳实践 == 1. 优先使用通道进行goroutine间通信 2. 对共享数据的访问保持简短 3. 使用<code>defer</code>确保锁一定会被释放 4. 考虑使用<code>sync.RWMutex</code>优化读多写少的场景 5. 使用<code>-race</code>标志检测竞态条件:<code>go run -race main.go</code> == 总结 == Go的内存同步机制为并发编程提供了强大的工具集。理解这些机制对于编写正确、高效的并发程序至关重要。通过合理使用互斥锁、通道和原子操作,可以构建出既安全又高性能的并发应用。 [[Category:编程语言]] [[Category:Go]] [[Category:Go 内存管理]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)