声明
转载请注明本文地址,感谢 :)
了解进程、线程、协程
本文不详细解释这三个名词的意思,下面有一篇文章,不懂的同学可以参考看看。
Goroutine的使用
|
|
没有输出?
- 执行了上面的代码后,你会发现,什么都没有输出,那么是什么问题呢?
因为我们当前的程序,只是一个单线程的程序,main函数只要执行完毕后,就不会再管其他线程在做什么事情了,程序自动退出。 然后我们想到了一个办法,加一个sleep函数,让main函数等待Goroutine函数执行完毕后再退出。
更改后的代码如下:
|
|
- 不出所料,程序成功打印出了“Goroutine”字符串。
引入Channel
- 通过上面的实验,我们成功地用Goroutine,并打印出了一句话。现在问题来了,这个并不是我们想要的。为什么?如果我的Goroutine函数里的代码需要执行10s、20s甚至更多的时候,怎么办?难道还是继续Sleep更多的秒数吗?
- 我们需要的是,当Goroutine函数执行完毕的时候,自动通知main函数。所以这里我们就引出了channel
创建方式
channel使用make创建
chann := make(chan bool)
往channel中传入数据
chann <- true
输出channel中的数据
<- chann
接着我们改进上面使用Sleep方式的代码,换成使用channel的版本
- 代码如下:
|
|
- 如果运行以上的代码片段后,你成功输出了Goroutine,那么说明我们的写法是没错的。现在我们来理解一下这段代码的意思,我们看看匿名函数外面的
<-chann
,这实际上是起到了阻塞的作用,当匿名函数里面的业务没有执行完并讲true传入channel中的时候,这个程序是不会退出的,匿名函数外面会一直在等待。当匿名函数里面执行到了chann <- true
,也就是将true传入了channel的时候,就不会继续阻塞,这时候程序就会结束。这就是channel的作用。
使用for range迭代输出Channel
- 需要注意的是,当你在对channel 迭代的时候,必须在某个位置明确的关闭这个channel,不然程序就会死锁。我们用一个代码段来示例一下:
|
|
Channel 的定义类型
- Channel 类型的定义格式:
ChannelType = ("chan" | "chan" "<-" | "<-" "chan")
- Channel包含了三种类型的定义,可选的<-代表的是Channel的方向。没有指定方向的话,Channel就是双向的,既可以接受数据,也可以发送数据。
chan T
//可以接收也可以发送chan <- bool
//可以发送bool类型的数据<- chan bool
//可以接收int类型的数据
无缓冲Channel与缓冲Channel
无缓冲Channel
- 定义方式
chann := make(chan int)
- 所谓无缓冲Channel就是在通道中只能传入1个值,若是传入的值一直没有被取走,那么就会一直阻塞着,直到被取走。可以说是同步阻塞的
- 需要注意的是,无缓冲Channel一定是先取后传。当代码中出现了取的操作时,发现Channel里面并没有值,那么就会发生阻塞,当Channel里有值了,才会停止阻塞。
缓冲Channel
- 定义方式
chann := make(chan int,100)
- 有缓冲Channel,比如缓冲值是100,那么除非传入的值已经达到了100了,否则这个Channel中,还是可以不断地传值进去。当Channel满了,就会发生阻塞,等值被取走后,才可以继续传值。
如何判断一组任务是否完成
使用缓冲Channel
|
|
使用sync包
- 通过设置一个任务组,大小为10。每完成一个任务就记录一次
wg.Done()
,当10个任务都完成的时候,程序自动退出。
|
|
Select
select 用于多个channel监听并收发消息,当任何一个case满足条件则会执行,若没有可执行的case,就会执行default,如果没有default,程序就会阻塞。
|
|
参考
- http://blog.csdn.net/gaox587/article/details/53005575
- http://blog.csdn.net/shachao888/article/details/52944212
- https://github.com/Unknwon/go-fundamental-programming/blob/master/lectures/lecture14.md
有疑问加站长微信联系(非本文作者)