Go语言调度器的工作原理
Go语言调度器的工作原理
Go语言的调度器是其并发模型的核心组件,负责管理goroutine的执行和调度。本文将深入探讨Go语言调度器的工作原理,包括GMP模型、goroutine并发模型以及为什么Go语言适合开发网游服务器端。
GMP模型
GMP模型是Go语言特有的线程模型。其中,P(Processor)与M(Machine)一般是一一对应的。P负责管理一组G(goroutine),并将它们挂载在M(内核线程)上运行。图中左边蓝色部分表示正在执行状态的goroutine,右边表示待执行状态的goroutine队列。
我们通过 go func()
来创建一个goroutine。调度器中包含两个存储G的队列:一个是局部调度器P的本地队列,另一个是全局G队列。
频繁创建线程会造成不必要的开销,因此Go语言采用了线程池的机制。Go程序启动时会申请一大块内存,并将其划分成spans、bitmap、arena区域。arena区域按页划分成一个个小块,span管理一个或多个页,mcentral管理多个span供线程申请使用,mcache作为线程私有资源,资源来源于mcentral。
Go语言采用两级线程模型,即用户线程与内核线程KSE(kernel scheduling entity)是M:N的。最终goroutine还是会交给OS线程执行,但是需要一个中介,提供上下文。
在Go调用C的时候,如果耗时比较长,会对Go的运行时造成一些副作用;在C回调Go的时候,Go的运行时也有可能阻塞C的回调线程。但Go的运行时已经比较成熟,因此这个问题的影响不大。
为什么Go语言适合开发网游服务器端
Go语言主要用作服务器端开发,其定位是用来开发“大型软件”的,适合于需要很多程序员一起开发,并且开发周期较长的大型软件和支持云计算的网络服务。
Go语言上手快,只要具备其他编程语言的基础,就能快速掌握。Go语言非常适合写服务端,因为它是开源的,很容易找到所需的框架,开发效率非常高。同时,Go语言具有跨平台特性,同一个程序可以在不同平台上部署。
Go语言的goroutine并发模型
Go语言采用两级线程模型,即用户线程与内核线程KSE(kernel scheduling entity)是M:N的。最终goroutine还是会交给OS线程执行,但是需要一个中介,提供上下文。
Go的CSP并发模型,是通过 goroutine和channel 来实现的。goroutine 是Go语言中并发的执行单位,其实就是协程。channel是Go语言中各个并发结构体(goroutine)之前的通信机制。
Go就是基因里面支持的并发,可以充分的利用多核,很容易的使用并发。内置runtime,支持垃圾回收,这属于动态语言的特性之一吧,虽然目前来说GC不算完美,但是足以应付我们所能遇到的大多数情况,特别是Go1之后的GC。
我们通过
go func()
来创建一个goroutine;有两个存储G的队列,一个是局部调度器P的本地队列、一个是全局G队列。