本篇笔记是笔者在第六届字节跳动青训营期间学习 Go 语言的语法笔记,主要内容为协程
1. 协程
1. 进程和线程
· 进程是操作系统分配资源的最小单元,线程则是运行的最小单位
· 笔者对这两者的理解是:进程本身包含这程序需要使用的资源,而线程仅仅是逻辑上执行某段代码的程序,其能够访问到的资源由外部的进程提供
2.并发和并行
· 并发是指单核 CPU 可以利用划分时间片与保留程序运行的上下文(当前运行环境)的方法,将用户可以宏观感受到的时间段划分为大量微小的时间片,每一个时间片在该核上只有一个进程工作,但由于不断地进行切换而导致用户在宏观感受上感觉有多个不同的进程在同时工作
· 并行是指多个进程在多个核中工作,在同一时刻(绝对时刻,并非用户感受),每个核有一个进程工作,由于有多核,因此在同一时刻,确实有多个不同的进程在同时工作,当然用户在这种情况下肯定会有和并发带来的相同的体验
3.协程
协程是 GO 语言中特有的可以不断执行一段代码的机制,笔者理解其为一种轻量低成本的线程,程序员可以在同一时间开启很多个协程,同时完成多个任务,且浪费相对于线程机制更少的资源
3.1 协程语法
首先,需要给出协程执行的代码,其为函数的形式:
func writeData(n int) {
for i := 0; i < n; i++ {
fmt.Println("writeData: ", i)
}
}
然后在主程序(main函数)中,启动协程执行上述代码,启动方式为直接在常规调用函数前增加 go 关键字即可:
go writeData(100)
还可以使用匿名函数的方式直接启动协程:
go func(n int) {
for i := 0; i < n; i++ {
fmt.Println("writeData: ", i)
}
}(100)
3.2 协程注意点
· 可以直接将协程理解为调用函数,只不过不再是主程序去执行了。而是主程序开启了一个协程,让协程去执行函数中的内容,主程序接下来继续向下执行即可
· 主程序和协程是同时执行的,程序员无法控制其先后,在书写程序层面,程序员不用关心这里到底是并发还是并行
· 当主程序(main 函数)执行完成时,不管有多少个协程还未执行完,程序都会结束,即未执行完的协程会被强制退出,且不发出任何警告
3.3 资源冲突,数据竞争
· 若同一资源被多个协程进行访问,很有可能在某一协程处理该资源的中途,该资源被交付到了另一协程中,且对其进行了更改,导致程序出现不符合预期的情况
· 若对同一资源的使用只有读取,则不会发生资源冲突的情况,因为没有协程会对数据修改
· 只要对同一资源的使用有写的情况,那么资源冲突是不可避免的,程序员必须要对该情况进行控制,否则,同一段程序的执行结果在多次调用后的处理效果是不一样的,且有时本地无法复现
· 锁的机制是多种语言应对资源冲突情况提供的机制,Go中也有类似机制。关于锁,笔者这里不去过多描述,因为 go 中提供了一种安全高效的类型:管道(channel) 来解决这一问题