golang的Channel
golang的ChannelChannel 是 golang 一个非常重要的概念,如果你是刚开始使用 golang 的开发者,你可能还没有真正接触这一概念,本篇我们将分析 golang 的Channel 1. 引入要讲 Channel 就避不开 Goroutine -- 协程。闲话不说, 直接上个例子 Goroutine demo: package main import ( "fmt" "time" ) func main() { origin := 1 go doSomeCompute(origin) time.Sleep(5 * time.Second) } func doSomeCompute(num int) { result := num * 2 fmt.Println(result) return } 简单来说,例子中有一个 main 的协程,一个 doSomeCompute 的协程。还有个延时退出的方法等待计算协程计算结果。我们尝试思考这个例子的一些问题: a. 如何获取 doSomeCompute 的计算结果? b. 如何获取 doSomeCompute 的执行状态,当前是执行完了还是执行中? 如何解决这种问题呢? Channel! 2. ChannelChannel怎么处理上面的问题?我们直接上代码: 举例 package main import ( "fmt" ) func main() { origin := 1 //一个无缓冲Channel res := make(chan int) go doSomeCompute(origin,res) fmt.Println(<-res) } func doSomeCompute(num int,res chan int) { result := num * 2 res <- result } 例子中,Channel 充当起了协程间通信的桥梁。Channel 可以传递到协程说明它是线程安全的,事实也是如此。Channel 可以理解为管道,协程 doSomeCompute 向 Channel 写入结果, main 中读取结果。注意,例子中读取 Channel 的地方会阻塞直到拿到计算结果,这样就解决了问题 a 和 b。 2. Channel 的方向性上面的例子中,计算协程是负责计算并将计算结果写入 Channel ,如果我们希望保证计算协程不会从 Channel 中读取数据该怎么处理?很简单,看例子: func doSomeCompute(num int,res chan<- int) { result := num * 2 res <- result } 这个参数的声明 3. 阻塞性质Channel 的读取和写入操作在各自的协程内部都是阻塞的。比如例子中 注意,无缓冲的 Channel 的读写都是阻塞的,有缓冲的 Channel 可以一直向里面写数据,直到缓存满才会阻塞。读取数据同理, 直至 Channel 为空才阻塞。 用一个典型的例子来说明缓冲和非缓冲 Channel 的区别: package main import "fmt" func doSomeCompute(ch chan int) { fmt.Println("deadlock test") <- ch } func main() { ch := make(chan int) ch <- 1 go doSomeCompute(ch) } 例子中,main 协程会向 fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send]: main.main() C:/mygo/src/demo/blog.go:12 +0x73 exit status 2 如果改成有缓冲的 Channel : package main import ( "fmt" "time" ) func doSomeCompute(ch chan int) { fmt.Println("deadlock test") <- ch } func main() { ch := make(chan int,1) ch <- 1 go doSomeCompute(ch) time.Sleep(1 * time.Second) } 有与有缓冲的 Channel 写入后不阻塞(下一次写入才会阻塞),程序会继续执行。 4. Channel 的数据结构Channel 在 golang 中实际上就是个数据结构。在 Golang 源码中, Channel 的数据结构 Hchan 的定义如下: struct Hchan { uint32 qcount; // total data in the q uint32 dataqsiz; // size of the circular q uint16 elemsize; bool closed; uint8 elemalign; Alg* elemalg; // interface for element type uint32 sendx; // send index uint32 recvx; // receive index WaitQ recvq; // list of recv waiters WaitQ sendq; // list of send waiters Lock; }; 时间仓促,这次对 Channel 介绍写的有点简单粗暴,下次再写。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |