跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
Go 内存模型
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= Go内存模型 = == 介绍 == Go内存模型(Go Memory Model)定义了Go程序中多个goroutine之间如何通过共享内存进行通信,以及内存操作的可见性和顺序性规则。它是理解并发程序行为的基础,尤其涉及数据竞争、同步原语(如通道和互斥锁)时至关重要。Go的内存模型基于'''happens-before'''关系,确保某些操作在另一些操作之前发生,从而避免未定义行为。 == 核心概念 == === Happens-Before关系 === 在Go中,如果操作A '''happens-before''' 操作B,那么A对内存的修改对B是可见的。以下是Go中建立happens-before关系的主要方式: 1. **初始化顺序**:`main`函数的执行happens-after所有包的`init`函数完成。 2. **goroutine创建**:`go`语句happens-before新goroutine的执行。 3. **通道通信**:发送操作happens-before对应的接收操作完成。 4. **互斥锁**:解锁操作happens-before后续的加锁操作。 === 数据竞争与同步 === 如果两个goroutine同时访问同一变量且至少一个是写操作,且未同步,则发生'''数据竞争'''。Go通过以下机制避免数据竞争: * **通道(Channel)**:通过通信共享内存。 * **互斥锁(Mutex)**:显式同步访问。 * **原子操作(atomic)**:低层同步原语。 == 代码示例 == === 通道同步示例 === 以下代码展示如何通过通道确保happens-before关系: <syntaxhighlight lang="go"> package main import "fmt" func main() { done := make(chan bool) msg := "" go func() { msg = "Hello, Go!" done <- true }() <-done fmt.Println(msg) // 输出: Hello, Go! } </syntaxhighlight> '''解释''': 1. goroutine中对`msg`的赋值happens-before发送`done <- true`。 2. 主goroutine中`<-done`接收happens-before`fmt.Println`,因此`msg`的值必然可见。 === 数据竞争示例 === 以下代码展示未同步导致的数据竞争: <syntaxhighlight lang="go"> package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup counter := 0 for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() counter++ }() } wg.Wait() fmt.Println(counter) // 可能输出小于1000 } </syntaxhighlight> '''修复方法''':使用`sync.Mutex`或原子操作(如`atomic.AddInt32`)。 == 实际应用场景 == === 并发计数器 === 在高并发场景中(如统计请求次数),需使用原子操作或互斥锁保护计数器: <syntaxhighlight lang="go"> package main import ( "fmt" "sync/atomic" ) func main() { var count int32 for i := 0; i < 1000; i++ { go func() { atomic.AddInt32(&count, 1) }() } // 等待所有goroutine完成(实际需用sync.WaitGroup) fmt.Println(atomic.LoadInt32(&count)) // 输出1000 } </syntaxhighlight> === 生产者-消费者模型 === 通过通道实现安全的并发数据传递: <syntaxhighlight lang="go"> package main import "fmt" func producer(ch chan<- int) { for i := 0; i < 5; i++ { ch <- i } close(ch) } func consumer(ch <-chan int) { for num := range ch { fmt.Println("Received:", num) } } func main() { ch := make(chan int) go producer(ch) consumer(ch) } </syntaxhighlight> == 可视化模型 == <mermaid> graph LR A[goroutine1: 写变量x] -->|happens-before| B[通道发送] B -->|happens-before| C[goroutine2: 通道接收] C -->|happens-before| D[goroutine2: 读变量x] </mermaid> == 数学表达 == Happens-before关系具有传递性:若A happens-before B且B happens-before C,则A happens-before C。用数学符号表示为: <math>A \rightarrow B \land B \rightarrow C \implies A \rightarrow C</math> == 总结 == Go内存模型通过happens-before规则和同步原语(通道、互斥锁、原子操作)确保并发程序的正确性。开发者需理解这些规则以避免数据竞争和未定义行为。 [[Category:编程语言]] [[Category:Go]] [[Category:Go 内存管理]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)