这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记
Go语言随着杀手级应用Docker在市场上的流行,被越来越多的开发者所熟知,但是Go语言更为重要的特性是其语法层面原生支持高并发,这使得Go语言将在未来受到更多的关注。
并发与并行
- 并行:指在同一时刻("同一时刻"指的是cpu的时间量级,也就是纳秒),有多条指令在多个处理器上同时执行。所以并行要借助多核cpu实现。
- 并发:指在同一时刻只能有一条指令执行,但是多个进程指令被快速的轮换执行,使得宏观上具有多个进程同时执行的效果,但是微观上不是同时执行的,只是把时间分成若干段,通过cpu时间片轮转使多个进程快速交替的执行。 并发其实又可以分为进程并发、线程并发以及协程并发。Go语言中所描述的并发机制更多是使用协程并发来实现,也就是goroutine。三者都可以实现并发,进程的好处在于稳定性,每个进程都是独立的,但是相较于线程来讲,开销很大。线程在切换时节省资源。协程在于效率高。所以在不同的应用场景中可以根据特定的需求选择不同的并发技术。
进程是操作系统分配资源的最小单位,线程是轻量级的进程。同时,线程是操作系统最小的执行单位。协程又可以理解为轻量级的线程,同进程、线程的设计初衷不同的是,协程的设计是为了提高程序执行的效率。
Goroutine
前面提到Go语言在语法层面原生支持高并发,就是通过Goroutine来实现。Goroutine创建于进程中,直接使用Go关键字放置于函数前面前面即可,这样就会产生一个新的goroutine,也叫go程。通过创建go程,使得子go程和主go程可以去争夺cpu的使用权限,在一个时间轮片范围内,哪一个go程争夺到了cpu资源,哪一个go程就会去执行。等到该go程执行完毕,又会在同一起跑线去争夺cpu资源,直至主go程执行完毕,子go程也会随之退出。下面通过课堂上老师所讲的一个例子了解一下goroutine。
//快速打印hello goroutine
func hello(i int) {
fmt.Println("hello goroutine:" + fmt.Sprint(i))
}
func main() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
//为了保证子协程在执行完之前,主协程不退出
time.Sleep(time.Second)
}
注意到为了保证在子协程可以顺利执行完毕,需要在主协程(main函数)中加入sleep函数保证给到子协程争夺cpu时间轮片的机会。后面也会有别的方式来替代sleep函数。
Goroutine调度
这里贴一下www.liwenzhou.com/posts/Go/co… 中对于goroutine调度的讲解图