go语言并发编程上
傍晚抽空学习了下go语言的并发编程,从goroutine到channel机制,从开始的稀里糊涂到现在拨开云雾见太阳的感觉,学习的过程总是令人亢奋的!当然目前的理解还是不够透彻的。下篇将举例来分析下。
goroutine
类似开辟进程、线程做法,go语言所采用的为 goroutine 。用法极其简单,也就是使用go关键字,使用方法有两种:
定义一个函数functionName,要异步调用时使用语句
go functionName
即可。使用匿名函数,用法为
go func(参数列表){函数执行体}()
,说明最后一个()
作用就是让该函数执行。
下面简单代码加深下:
/////////第一种示例代码:///////////
func sayHello(name string){
fmt.Println("hello"+name)
}
//主程序入口
func main(){
go sayHello("PMST")
}
/////////第二种示例代码://////////
//主程序入口
func main(){
go func(){
fmt.Println("hello world")
}() //别忘记这里的()
}
现在来讲下go关键字作用,一旦将go放在函数之前,意味分配一个子routine让这个函数自个玩去(有点自身自灭的感觉),而主routine则继续该干嘛干嘛。打个比方,手头有一堆数据,需要经过超级复杂,超级耗时的计算才能得出答案。显然我们的主routine不可能只干这一件事,它还有其他事情需要处理。因此,我们开辟一个routine让其自个算去。
那么问题来了,这么做确实解决了主routine不被锁死的问题,又能够完成了耗时计算,可是计算出答案之后,如何回传给主routine使用呢?
这也就是下面channel的使用了
channel
goroutine 之间如何进行数据的通信?如下两种:
共用内存内存空间。
Go语言推荐的通信机制channel。
接下来是我对channel的一些理解:
Goroutine使用channel 接收或者发送值,而这些值只能是特定的类型,由自己指定,比如两个routine之间相互传值为int类型,那么channel类型就是
chan int
通过make来创建channel,例如无缓存
ci := make(chan int)
,指定缓存cib := make(chan int,2)
。很明显可以看出,区别在于后面的表述,后者表示给这个通道分类了2个缓存空间,至于区别,下文马上给出。channel 通过
<-
来接收和发送数据。例如channel <- value
,显然就是把值 value 发送到通道 channel 中;value := <- ch
,注意箭头,表示从通道 channel 读取数据给 value ,或者可以说从通道channel接收数据赋值给value。顺便提及其他的写法<- channel
,显然也是从通道读取数据,但是没有赋值给任何一个变量,因此表示丢弃!
关于channel的阻塞问题,我想有必要着重梳理下。请看下面的总结
首先通道的接收和发送都是阻塞的,除非与之对应的一端已经准备好。通过举例来说明是最好不过了。
新建一个通道,
channel_c := make(chan int)
,注意是没有分配缓存的。随后往通道写入数据,
channel_c <- value
,由于没有分配缓存,因此这里会被堵塞掉,换句话说就是卡死在这里,只能等待,等待程序某个地方从该通道读取数据!(ps:就好比非常短的管子,就往里塞了一个数据,就要漏出来,因此我一直手”扶着”数据,腾不出手干下面的事了。只有当接收方来拿数据了才能腾出手来干别的事。)2015.04.22 -> 对上面比喻修改。ps:上面比喻的不是很恰当,我想是不是可以这么认为,channel是连通两个routine的通道,当发送者向channel里发送数据,却迟迟等不到接收者,但秉着尽职尽责的思想,始终等待在那个位置,即
channel_c <- value
这条发送语句处,直到接收者接收了通道数据,才可以进行下一条语句。那么假如有缓存就不同了,就好比一个驿站,拿着数据到通道这发送“邮件”,尽管可能没有接收者,但是我却可以先暂时放到“驿站”(缓存)这里,然后继续干自己的活,等下次再向通道发送数据时发现缓存满了,就只能耐心等待,除非这时有人来取数据,腾出缓存空间了,才可以写入数据。现在换成从通道读取数据,
v := <- channel_c
,分两种情况:当channel_c通道中有数据时,那肯定不会堵塞,很顺利的读过来;当channel_c通道没有数据时,那么自然又堵死了,除非程序其它地方往通道写入数据了!最后讲讲关于分配了缓存的通道,例如:
channel := make(chan int,2)
。假如这时候往通道写入数据channel <- 2
,由于分配了缓存,意味着是我可以直接写入,不会堵塞了,但这仅当我的缓存区未满的情况下才不会堵塞。下面往通道写入一个channel <- 3
,这是没有问题的。不过缓存已经填满了!假如这时候你再写的话就会堵塞,只有程序某个地方从改通道读取数据腾出地方了,你才可以写入!
有疑问加站长微信联系(非本文作者)