携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
基础概念
- 并发:简单说,同一时刻下同时做几件事情。如边听音乐边写掘金文章
- 进程:就是操作系统中正在执行中的一个程序。比如打开的浏览器
- 线程:是进程的执行空间,一个进程可以有多个线程。
程序被启动时就会有对应的进程被创建,同时也会启动一个线程,即主线程。主线程结束整个程序就会退出。主线程启动后会启动其他的线程,这些线程就是进程运行时需要的。
- 协程:Go 中没有线程的概念,只有协程,即 goroutine。
协程,比线程更加轻量,一个程序可以随意启动成千上万个协程。
线程是由操作系统进行调度的,而协程是由 Go runtime 调度的。可以自由控制执行任意个 goroutine,何时执行。
协程
启动协程 goroutine 使用关键字 go
func action(){
// doing something
}
// 启动 goroutine
go action()
go 关键字后面跟一个方法或者函数的调用,就可以启动一个 goroutine 。需要注意启动协程是并发的过程,其不阻塞主线程的执行。所以以下完整例子,你会得到结果:
func main(){
go fmt.Println("我是协程1")
fmt.Println("主协程执行中...")
// 使用time让主线程等待1秒,主要为了协程执行完后再结束主线程
time.sleep(time.second)
}
// 执行结果
主协程执行中...
我是协程1
启动了多个协程 goroutine 之后,多个协程之间如何通信呢?
通道 Channel
使用内置的 make 函数声明一个 channel,关键字 chan 表示 channel 类型。
ch := make(chan string)
chan 的操作只有 2 种:
- 接收:获取 chan 中的值,操作符 <-chan
- 发送:向 chan 发送值,操作符 chan <-
以上代码,使用关键字 make 创建了一个无缓存 channel ,它的容量是 0,不能存储任何数据。
- 无缓存 channel,即为同步 channel ,因其容量是0,只能进行传输数据,不存储数据,所以发送和接收是同时进行的,所以称为同步 channel
- 有缓存 channel ,说明支持存储数据
ch := make(chan string, 5)
有缓存 channel 的内部有一个缓存队列,类似是一个队列,先进先出。当队列为空时则阻塞等待,直到接收到新的元素;当队列满时,也会阻塞等待,直到读取队列或释放。
close(ch)
关闭 channel ,直接调用内置函数close ,关闭后就无法接收数据,再发送数据就会引起 panic 异常。