golang的Channel
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介绍写的有点简单粗暴,下次再写。
原文链接: