首页 文章资讯内容详情

golang的Channel

2026-06-01 4 花语

golang的Channel

Channel是golang一个非常重要的概念,如果你是刚开始使用golang的开发者,你可能还没有真正接触这一概念,本篇我们将分析golang的Channel

1.引入

要讲Channel就避不开Goroutine--协程。闲话不说,直接上个例子

Goroutinedemo

packagemain import( "fmt" "time" ) funcmain(){ origin:=1 godoSomeCompute(origin) time.Sleep(5*time.Second) } funcdoSomeCompute(numint){ result:=num*2 fmt.Println(result) return }

简单来说,例子中有一个main的协程,一个doSomeCompute的协程。还有个延时退出的方法等待计算协程计算结果。我们尝试思考这个例子的一些问题:

a.如何获取doSomeCompute的计算结果?

b.如何获取doSomeCompute的执行状态,当前是执行完了还是执行中?

如何解决这种问题呢?

Channel!

2.Channel

Channel怎么处理上面的问题?我们直接上代码:

举例

packagemain import( "fmt" ) funcmain(){ origin:=1 //一个无缓冲Channel res:=make(chanint) godoSomeCompute(origin,res) fmt.Println(<-res) } funcdoSomeCompute(numint,reschanint){ result:=num*2 res<-result }

例子中,Channel充当起了协程间通信的桥梁。Channel可以传递到协程说明它是线程安全的,事实也是如此。Channel可以理解为管道,协程doSomeCompute向Channel写入结果,main中读取结果。注意,例子中读取Channel的地方会阻塞直到拿到计算结果,这样就解决了问题a和b。

2.Channel的方向性

上面的例子中,计算协程是负责计算并将计算结果写入Channel,如果我们希望保证计算协程不会从Channel中读取数据该怎么处理?很简单,看例子:

funcdoSomeCompute(numint,reschan<-int){ result:=num*2 res<-result }

这个参数的声明chan<-int就表示该函数只能讲数据写入Channel,而不能从中读取数据。后面的int表示Channel中数据的格式。同样的,只可以读取数据的Channel可以声明为<-chanint。而例子中不带有方向声明的Channel则既可以写入也可以读取。

3.阻塞性质

Channel的读取和写入操作在各自的协程内部都是阻塞的。比如例子中fmt.Println(<-res),这一语句会阻塞直至计算协程将计算结果放入,可以读出。也就是说,协程会阻塞直至从res中读出数据。

注意,无缓冲的Channel的读写都是阻塞的,有缓冲的Channel可以一直向里面写数据,直到缓存满才会阻塞。读取数据同理,直至Channel为空才阻塞。

用一个典型的例子来说明缓冲和非缓冲Channel的区别:

packagemain import"fmt" funcdoSomeCompute(chchanint){ fmt.Println("deadlocktest") <-ch } funcmain(){ ch:=make(chanint) ch<-1 godoSomeCompute(ch) }

例子中,main协程会向ch写入数据,这一过程是阻塞的,也就是说,doSomeCompute协程无法执行,程序死锁。输出如下:

fatalerror:allgoroutinesareasleep-deadlock! goroutine1[chansend]: main.main() C:/mygo/src/demo/blog.go:12+0x73 exitstatus2

如果改成有缓冲的Channel:

packagemain import( "fmt" "time" ) funcdoSomeCompute(chchanint){ fmt.Println("deadlocktest") <-ch } funcmain(){ ch:=make(chanint,1) ch<-1 godoSomeCompute(ch) time.Sleep(1*time.Second) }

有与有缓冲的Channel写入后不阻塞(下一次写入才会阻塞),程序会继续执行。

4.Channel的数据结构

Channel在golang中实际上就是个数据结构。在Golang源码中,Channel的数据结构Hchan的定义如下:

struct Hchan { uint32 qcount; //totaldataintheq uint32 dataqsiz; //sizeofthecircularq uint16 elemsize; bool closed; uint8 elemalign; Alg* elemalg; //interfaceforelementtype uint32 sendx; //sendindex uint32 recvx; //receiveindex WaitQ recvq; //listofrecvwaiters WaitQ sendq; //listofsendwaiters Lock; };

时间仓促,这次对Channel介绍写的有点简单粗暴,下次再写。

原文链接: