为什么需要channel?
前面使用全局变量加锁同步来解决goroutine的通讯,但不完美。
(1)主线程在等待所有goroutine全部完成的时间很难确定,我们这里设置10秒,仅仅是估算。
(2)如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有goroutine处于工作状态,这时也会随主线程的退出而销毁。
(3)通过全局变量加锁同步来实现通讯,也并不利于多个协程对全局变量的读写操作。
(4)上面种种分析都在呼唤一个新的通讯机制——channel。
一、channel的介绍
1、channel本质上就是一种数据结构——队列。
2、数据是先进先出。
3、线程安全,多goroutine访问时,不需要加锁,就是说channel本身就是线程安全的。
4、channel是有类型的,一个string的channel只能存放string类型数据。
示意图二、管道的基本使用
1、定义/声明channel
channel的定义和声明2、初始化
channel的初始化3、向channel中写入(存放)数据
向channel中写入(存放)数据4、channel使用的注意事项
(1)channel中只能存放指定的数据类型。
(2)channel的数据放满后,就不能再放入了。
(3)如果从channel取出数据后,可以继续放入。
(4)在没有使用协程的情况下,如果channel数据取完了,再取,就会报dead lock。
5、channel的遍历和关闭
关闭和遍历关闭例程如下:
关闭例程遍历例程如下:
关闭例程三、channel的案例演示
1、创建一个intChan,最多可以存放3个int,演示存3个数据到intChan,然后再取出这3个int:
示例2、创建一个mapChan,最多可以存放10个map[string]string的键值对,演示写入和读取:
示例3、创建一个catChan,最多可以存放10个Cat结构体变量,演示写入和读取的用法:
示例5、创建一个allChan,最多可以存放10个任意数据类型变量,演示写入和读取的用法:
示例四、管道的使用细节和注意事项
1、channel可以声明为只读或者只写性质
只写的管道 只读的管道2、channel只读和只写的最佳实践案例
最佳写法main方法中,有send和recv两个协程。send中需要穿恶毒管道ch参数,如果我们希望它是只写的,可以在定义send函数的时候写明参数ch chan<- int,这样ch在函数内就是只写而不能被读取了。这样的做法可以防止误操作。recv协程同理,我们希望管道ch是只读的,可以在定义recv函数的时候写明参数ch <-chan int。
3、使用select可以解决从管道取数据的阻塞问题。
示例上半部 示例下半部 输出4、goroutine中使用recover,解决协程中出现panic,导致程序崩溃问题。
如果我们起了一个协程,但是这个协程出现了panic,如果这个协程出现了panic,如果我们没有捕获panic,就会造成整个程序崩溃,这时我们可以在goroutine中使用recover来捕获panic,进行处理,这样即使这个协程发生了问题,主线程仍然不受影响,可以继续执行。
示例这个示例中,画红线的这一行代码将来在执行时就会出错,因为map还没有用make分配空间就给它赋值了,最后test()协程会出错,进而造成整个主线程的崩溃停止运行。
修改后这里用defer和recover解决了这个问题,出错了,返回输出一个错误即可,整个主线程还在继续执行。
输出输出如下所示,虽然test()发生了错误,但是主线程依旧继续执行。
网友评论