发布时间:2024-12-04 01:02:49
在Golang中,开发者可以通过关键字go创建一个Goroutine,它是一个轻量级的执行单元。每一个Goroutine都会被调度器分配给一个系统线程来执行,这样就实现了并发执行。
M代表了系统线程,也即操作系统内核线程。G代表了Goroutine,是调度器调度的执行单元。P代表了上下文,它维护了调度器的状态信息,包括可运行的Goroutine队列、当前正在执行的Goroutine等。
当一个Goroutine被调度器创建时,调度器会将它加入到P管理的运行队列中。P会根据一定的策略选择一个可运行的Goroutine,并将其绑定到一个M上,使其在这个M上执行。当这个Goroutine执行完成或者发生阻塞时,M会将它解绑,让出资源给其他Goroutine。
工作窃取调度策略是一种负载均衡算法,它尽量保证每个M上的Goroutine都在忙碌。当某个M上的Goroutine执行完成后,这个M可以从其他M的运行队列窃取一个Goroutine执行,以保证自己不闲置。这样可以实现Goroutine的动态负载平衡,提高系统并发度。
当一个Goroutine执行的时间超过一定阈值时,调度器会主动触发抢占,将当前执行的Goroutine挂起,并将资源让给其他Goroutine。这样可以避免长时间运行的Goroutine占据系统线程,导致其他Goroutine得不到执行的机会。
其中一个优化是休眠Goroutine的抢占。当一个Goroutine进入休眠状态(如等待网络IO、等待锁等)时,它不会被调度器主动抢占。休眠的Goroutine会自动放弃CPU资源,等到唤醒后再次参与竞争。这样可以减少上下文切换的开销,提高系统的整体效率。
另外一个优化是工作窃取的实现。调度器会通过一种巧妙的方式将可运行的Goroutine队列分成多个子队列,每个M只能访问自己所属的子队列。这样可以减少并发访问队列的冲突,提高工作窃取的效率。