Go语言与高并发 | 青训营笔记

75 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

Go语言为什么适合高并发???

并发与并行

并发:多线程程序在单核CPU上工作运行,交替式占用时间片

image.png 并行:多线程程序在多核CPU上同时工作运行

image.png Go语言在这方面可以充分发挥多核优势

Goroutine

image.png 协程:用户态、轻量级线程、栈MB级别 线程:内核态、线程包括多个协程、栈KB级别

代码示例

我们先来看看在go中实现并发操作到底有多简单,来看代码:

func main()  {
   go add(3,6)  
   go add(1,6)  
   time.Sleep(time.Second)
}
func add(a int,b int)  {
   result := a+b
   fmt.Println(result)
}

go关键字实现了协程开辟调用,如果不进行等待,主线程结束,协程就会马上结束。

go的并发

其实go语言中的goroutine就是参考的(Communicating Sequential Process)模型,原始的CSP中channel里的任务都是立即执行的,而go语言为其增加了一个缓存,即任务可以先暂存起来,等待执行进程准备好了再逐个按顺序执行。 但其实go语言并没有完全实现了CSP模型的所有理论,仅仅是借用了 process和channel这两个概念。process是在go语言上的表现就是 goroutine 是实际并发执行的实体,每个实体之间是通过channel通讯来实现数据共享。

- 1)goroutine

Goroutine 是go实际并发执行的实体,它底层是使用协程(coroutine)实现并发,coroutine是一种运行在用户态的用户线程,go底层选择使用coroutine的出发点是因为,它具有以下特点:

  • 用户空间 避免了内核态和用户态的切换导致的成本
  • 可以由语言和框架层进行调度
  • 更小的栈空间允许创建大量的实例

- 2)channel

go中使用了 CSP中的 channel 。channel 是被单独创建并且可以在进程之间传递,它的通信模式类似于 boss-worker 模式的,一个实体通过将消息发送到channel 中,然后又监听这个 channel 的实体处理,两个实体之间是匿名的,这个就实现实体中间的解耦,其中 channel 是同步的一个消息被发送到 channel 中,最终是一定要被另外的实体消费掉的,在实现原理上其实是一个阻塞的消息队列。

- 3)调度器

goroutine是在golang层面提供了调度器,在调度器加入了steal working 算法 ,goroutine是可以被异步抢占,因此没有函数调用的循环不再对调度器造成死锁或造成垃圾回收的大幅变慢。并且go对网络IO库进行了封装,屏蔽了复杂的细节,对外提供统一的语法关键字支持,简化了并发程序编写的成本。

总结

Golang实现了 CSP 并发模型做为并发基础,底层使用goroutine做为并发实体,goroutine非常轻量级可以创建几十万个实体。实体间通过 channel 继续匿名消息传递使之解耦,在语言层面实现了自动调度,这样屏蔽了很多内部细节,对外提供简单的语法关键字,大大简化了并发编程的思维转换和管理线程的复杂性。