这里卡了好久,是因为 进程、线程以及协程 的关系较为难以用文字表达出来。
什么是协程
要弄清楚什么是协程,我们需要先了解下进程 和 线程 之间的关系,我们从内存的角度来看待该问题,我们都知道,进程是操作系统进行资源分配和调度的基本单位。 并且其程序虚拟内存分布图大致如下
线程是操作系统能够进行调度的最小单位,一个进程至少有一个线程,在上述虚拟内存分布图中,线程会在栈区分配一块区域来存放数据,其他资源则和其他线程共享,例如: 代码段、数据段 以及 堆,其虚拟内存分布大致如下
协程,也称之为用户态线程或则说轻量级线程,顾名思义,协程是在用户态中自己维护的,系统调用则是通过线程去调用的。这样好处为对于内存而言,申请协程,比申请线程内存开销要小得多。
go 协程
开启协程
在golang
中,使用关键字go
开启协程,例如
我们执行程序后,输出为
在go
中,我们通常将main
函数称之为主协程,在主协程中调用其他协程序,我们协程给的次数是100(go worker("斜程处理中",100)),值得注意的是,当主协程执行完毕后,其他协程也给关闭了,我们可以将执行过程整理图示如下:
那么,我们是否有方法等待协程结束呢? 有的
等待协程执行完毕
我们可以使用sync.WaitGroup
来等待协程执行完毕后再执行下面的语句,其方法名和具体含义为
- (wg *WaitGroup) Add(delta int)
将delta
增加到waitgroup
计数器,该值可能为负数
- func (wg *WaitGroup) Done()
等同于 (wg *WaitGroup) Add(-1)
- func (wg *WaitGroup) Wait()
会持续等待,直至waitgroup
计数器为0
我们来写一个等待协程执行完毕的例子
这里有个点,我们为什么将wg.Add(1)
放到匿名函数之外呢,如果我们放到匿名函数里面,协程压根就不会跑就结束了。
我们执行下
协程序小案例
具体代码参见: gitee.com/pdudo/golea…
我们早些时候学习shell
的时候,写过多进程拷贝文件且打包的案例,这里将shell
代码贴过来一下
其具体逻辑为:
我们重新用go
协程来写一下,这里贴一下用协程拷贝文件的代码
具体的可以查看详细代码
总结
我们今天了解了什么是进程、线程 和 协程序(我现在还是晕晕乎乎的),除此之外,我们还了解了go
协程,我们可以将main
函数看做一个主协程,在主协程中开启其他协程,当主协程执行完毕后,会结束其他协程执行,以及sync.WaitGroup
计数器,最后我们通过一个拷贝案例来逐步了解go
协程应用。