Go 语言中 channel 内存模型

简介: Go 语言中 channel 内存模型

内存模型


Go 内存模型描述的是 “在一个 groutine 中对变量进行读操作能够侦测到在其他 gorountine 中对改变量的写操作” 的条件。


happen-before定义


To specify the requirements of reads and writes, we define happens before, a partial order on the execution of memory operations in a Go program. If event e1 happens before event e2, then we say that e2 happens after e1. Also, if e1 does not happen before e2 and does not happen after e2, then we say that e1 and e2 happen concurrently.


这是 Happens Before 的定义,如果 e1 发生在 e2 之前,那么我们就说 e2 发生在 e1 之后,如果 e1 既不在 e2 前,也不在 e2 之后,那我们就说这俩是并发的.

关于channel的happens-before在Go的内存模型中提到了三种情况:

  • case1: 对一个channel的发送操作 happens-before 相应channel的接收操作完成
  • case2: 关闭一个channel happens-before 从该Channel接收到最后的返回值0
  • case3: 不带缓冲的channel的接收操作 happens-before 相应channel的发送操作之前


case1:对一个channel的发送操作 happens-before 相应channel的接收操作完成


测试代码:

import "testing"
var c = make(chan int, 10)
var a string
func f() {
 a = "hello, world" // (1)
 c <- 0             // (2) 写操作 发送操作
}
func TestMemoryModel(t *testing.T) {
 go f()
 <-c      // (3) //接收操作
 print(a) // (4)
}

上面的代码,将保证会打印出 hello world 。有缓冲 channel 写操作发生在接收操作之前。


不带缓冲的channel的接收操作 happens-before 相应channel的发送操作之前


var c1 = make(chan int)
var a1 string
func f1() {
 a1 = "hello, world" // (1)
 <-c1                // (2) 接收操作
}
func TestMemoryModel1(t *testing.T) {
 go f1()
 c1 <- 0   // (3) 发送操作
 print(a1) // (4)
}


运行结果:


=== RUN   TestMemoryModel1
hello, world--- PASS: TestMemoryModel1 (0.00s)
PASS


上面的代码将保证会打印出 hello world 。因为

根据上面的第三条规则(2) happens-before (3),最终可以保证(1) happens-before (4)。

无缓冲 channel 接收操作发生在写操作之前。


再看个例子


var c2= make(chan int, 1)
var a2 string
func f2() {
 a2 = "hello, world"  // (1)
 <-c2   //  接收操作
}
// 不能保证 打印出 "hello, world"
func TestMemoryModel2(t *testing.T) {
 go f2()
 c2 <- 0  // (3)
 print(a2)  // (4)  写操作
 //var day  time.Time
 //print(day.Format("20060102"))
}


上面的代码不能保证打印出 hello world , 因为输出的channel 是有缓冲的,不能保证接收操作发生在写操作之前,但是能保证写操作发生在接收操作之前。

相关文章
|
1月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
152 1
|
3月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
286 1
|
9月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
3月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
359 0
|
3月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
232 0
|
3月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
212 0
|
3月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
305 0
|
3月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
3月前
|
Go 开发者
Go语言实战案例:使用select监听多个channel
本文为《Go语言100个实战案例 · 网络与并发篇》第5篇,详解Go并发核心工具`select`的使用。通过实际案例讲解如何监听多个Channel、实现多任务处理、超时控制和非阻塞通信,帮助开发者掌握Go并发编程中的多路异步事件处理技巧。
|
3月前
|
数据采集 编解码 监控
Go语言实战案例:使用channel实现生产者消费者模型
本文是「Go语言100个实战案例 · 网络与并发篇」第4篇,通过实战案例详解使用 Channel 实现生产者-消费者模型,涵盖并发控制、任务调度及Go语言并发哲学,助你掌握优雅的并发编程技巧。

热门文章

最新文章

下一篇
oss云网关配置