社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
golang的最大特点之一就是天然支持基于goroutine的高并发操作。本文将介绍goroutine的相关知识。
并发:相同的处理器顺序处理多个任务,可以理解为左手拿面包,右手拿啤酒,由于只有一张嘴,所以嘴是并发的吃。 并行:不同的处理器同事处理多个任务,可以理解为左手画圆,右手画方,左右手是并行的行动。
进程:操作系统管理,可以近似认为是程序所有代码的一次动态执行;线程:操作系统管理,可以近似认为是程序部分代码的一次动态执行; 协程:程序自行管理,可以近似认为是程序任意函数的一次动态执行; goroutine:系统和程序共同管理,系统管理资源调度等,程序管理应用逻辑;是golang自行封装过的协程,可以近似认为是协程,以下均称协程。
如下所示,在golang中起一个协程非常简单
func
每次通过Sleep等待协程执行结束是不现实的,因为实际中我们无法判断协程何时结束,所以引入WaitGroup来监控协程的执行状态。WaitGroup内部维护一个计数器,通过Add()、Done()和Wait()对计数器进行加1、减1和阻塞等待操作,当计数器为0时,所有协程执行完毕,则主程序结束。
import
那协程之间如何竞争资源和通信呢?传统方法是通过共享锁或互斥锁竞争资源,而在golang中建议使用channal,同时golang团队建议:不要通过共享内存来通信,而是通过通信来共享内存。这怎么理解呢?不要试图通过控制内存的使用权限来进一步获取内存数据,而是各个协程利用通信机制直接获取内存数据达到共享的目的。通常我们利用加锁来获取某个变量、代码或内存的使用权,从而获得数据;而在golang中,我们直接通过channal通信获取数据。
channal(通道)
通道按功能可以分成只读、只写和可读可写三种,按容量可以分为有缓冲和缓冲两种。
//模板,声明双向通道
channal的读写权限主要看“箭头”的方向,“箭头”方向就是数据流动的方向。
ch
很多同学有疑问,不能写入,那只读通道从哪儿读呢,或者不能读取,只写通道的数据又有什么意义呢?其实在使用时,只读和只写通道都是基于可读可写通道的,只是赋予的功能不同。例如上面的代码,对chWrite的写入实际是对ch的写入,对chRead读取实际是对ch的读取。也就是对ch的读写操作都通过chWrite和chRead完成。
多协程协同工作时,利用公共的channal通信共享数据。
var
channel 和 select
select是golang的一个关键字,常常与channal一起使用,主要的作用类似switch等选择语句,但在使用时有几点特性:
1、case后的表达式必须是通信。
2、所有channal表达式都会被求值。
3、当一个或多个case满足条件时,会随机选一个执行。
4、如果有default,则当无case满足条件时执行;若没有defualt语句,则select将阻塞,直到某个case满足条件。
ch1
如上代码所示:
1、三个case都是通信
2、三个case都是channal表达式(2次写入和1次读取),都会被求值;
3、三个case都满足,则随机挑选一个执行,故多次执行后输出可能不同。
ch4
4、如上所示,有default语句且其他case语句不满足,则执行default语句输出“case default”;如果没有default语句,那么1秒之后,第二个case语句满足,则会输出“case timeout”,这也是select常见的用法之一:判断超时。
channal的循环:
ch
for循环是golang语言中的唯一循环结构,同时在channal写完毕后需要close,类似文件读取完成后需要关闭,否则之后若发生读取操作,则会发生panic;同时close过的通道不能被再次close。
另外大家可以发现元素v的地址输出都相同,所以如果需要穿参数,那一定要传值喔,不能传地址。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!