goroutine调度

WoLannnnn WoLannnnn     2023-02-02     732

关键词:

文章目录


Go 的调度器模型一开始是一个简单的模型:G-M 模型,后来因为性能的问题被弃用了,现在的调度器模型是 G-P-M 模型

G-M 模型

我们用 G 表示 goroutine,M 表示 thread 线程,下图是 G-M 模型的的实现:

M 想要执行、放回 G 都需要先申请锁,然后从全局队列获取/放回 G。因为 M 有多个,所以在访问全局队列的时候需要锁来完成互斥/同步。

G-M 模型的缺点:

  1. 频繁的申请锁会造成激烈的竞争
  2. G 在不同 M 直接的切换会造成延迟和额外的系统负载。比如 M 上运行的 G 创建了 G’,G’ 就需要给其他 M 执行,此时会造成很差的 “局部性”,因为 G’ 与 G 是相关的,所以最好和 G 在同一个 M 上运行
  3. 系统调用(CPU 在 M 之间的切换)导致频繁的线程阻塞和取消阻塞增加了的系统开销

G-M-P 模型

G-M-P 引进了 P(processor 处理器),P 包含了运行 goroutine 的资源,它有一个本地队列,本地队列里存放了可运行的 G。

下面是 G-M-P 模型原理:

全局队列:存放可运行的 G

本地队列:也是存放可运行的 G,不过有数量限制,最多为 256 个,新创建的 G 优先放入本地队列中,如果本地队列满了,则会将队列中一半的 G 放入全局队列中

P:所有的 P 都在程序启动时创建,并保存在数组中,最多可创建 GOMAXPROCS 个。GOMAXPROCS 可通过 GO 环境变量和 runtime 包的 GOMAXPROCS 函数设置

M:M 要运行 G 就要选择与一个 P 绑定,然后从 P 的本地队列中拿走 G 并运行,运行完后再拿走下一个 G,如此往复。如果 P 的本地队列为空,则 M 可能会从全局队列中一批 G 放入 P 的本地队列,也可能会从其他 P 的本地队列中一半放到与自己 P 绑定的本地队列中

goroutine 调度器是通过 M 与 OS 调度器结合起来的,每个 M 代表了一个内核线程,OS 调度器负责吧内核线程分配到 CPU 的核上运行。

P 和 M 何时创建

P:当确认了最多可创建的 P 个数 n 之后,运行时系统会根据这个值创建 n 个 P

M:没有足够的 M 来关联 P 运行 P 的本地队列中的 可运行的 G 时。比如现在所有的 M 都在运行,而还有 P 的本地队列中有空闲的 G,P 会去找空闲的 M,如果找不到就会创建一个新的 M

调度器设计策略

复用线程:避免频繁地创建、销毁线程,而是对线程复用

  1. work stealing 机制

    当线程绑定的 P 本地队列中为空的时候,可以从其他已绑定的 P 中偷一半的 G 到自己绑定的 P 的本地队列中来运行,而不是销毁

  2. hand off 机制

    当线程因为 G 进行系统调用而阻塞时,线程会释放绑定的 P(线程与 G 一起阻塞),转移给其他空闲的线程处理

  • 利用并行

    GOMAXPROCS 设置 P 的数量,最多有 GOMAXPROCS 个线程分布在多个 CPU 上运行。

  • 抢占式调度

    一个 goroutine 最多占用 CPU 10 ms,防止其他 goroutine 饿死。

  • 全局队列

    当线程在进行 work stealing 工作的时候,如果从其他 P 中偷不到 G ,就会从全局队列中获取 G

参考

也谈 goroutine 调度器

Golang 调度器 GMP 原理与调度全分析

golang的goroutine调度机制

golang的goroutine调度机制2016年09月26日14:28:08阅读数:5664一直对goroutine的调度机制很好奇,最近在看雨痕的golang源码分析,(基于go1.4)感觉豁然开朗,受益匪浅;去繁就简,再加上自己的一些理解,整理了一下~~调度器主要基于三个... 查看详情

goroutine调度

...了,现在的调度器模型是G-P-M模型G-M模型我们用G表示goroutine,M表示thread线程,下图是G-M模型的的实现:M想要执行、放回G都需要先申请锁,然后 查看详情

goroutine调度

...了,现在的调度器模型是G-P-M模型G-M模型我们用G表示goroutine,M表示thread线程,下图是G-M模型的的实现:M想要执行、放回G都需要先申请锁,然后 查看详情

goroutine调度

...了,现在的调度器模型是G-P-M模型G-M模型我们用G表示goroutine,M表示thread线程,下图是G-M模型的的实现:M想要执行、放回G都需要先申请锁,然后 查看详情

goroutine的调度

本文整理自TheGoschedulerGoroutine的调度Go语言之所以要自己实现一个调度器有以下两个原因:协程调度。因为系统内核不能再决定协程的切换,那么协程的切换时间点则是由程序内部的调度器决定的。垃圾回收。垃圾回收的... 查看详情

go中的特殊协程g0

...术A【译文】原文地址本文基于go1.13版本所有在Go中创建的goroutines都由一个内部调度程序的管理。Go调度程序试图给所有的goroutines分配运行时间,并且在当前goroutine被阻塞或终止情况下也能使CPU忙于运行其他goroutines。Go通过GOMAXPRO... 查看详情

[日常]go语言圣经-goroutines和线程

Goroutines和线程:1.动态栈: 1)线程都有一个固定大小的内存块(一般会是2MB)来做栈 2)一个goroutine会以一个很小的栈开始其生命周期,一般只需要2KB,不是固定的;栈的大小会根据需要动态地伸缩2.Goroutine调度: 1)线程是使用硬件定时器... 查看详情

golang控制goroutine调度顺序(代码片段)

使用go关键字就可以很容易的启动一个goroutine,启动后他们的执行顺序是不能保证的。如果有多个goroutine,怎样按照我想要的顺序来执行呢?如:a1在b1和c1后面执行(b1和c1都执行完a1才能执行)d1在a1后面执... 查看详情

go并发编程(代码片段)

并发编程GoroutineGoroutine是Go语言特有的并发体,是一种轻量级的线程,由go关键字启动。在真实的Go语言的实现中,goroutine和系统线程也不是等价的。一个Goroutine会以一个很小的栈启动(可能是2KB或4KB),当遇到深度递归导致当前... 查看详情

go语言——goroutine并发模型

参考技术A参考:Goroutine并发调度模型深度解析&手撸一个协程池Golang的goroutine是如何实现的?Golang-调度剖析【第二部分】OS线程初始栈为2MB。Go语言中,每个goroutine采用动态扩容方式,初始2KB,按需增长,最大1G。此外GC会收缩栈... 查看详情

go协程(goroutine)调度原理(代码片段)

...,可能很多Gopher都好奇Go运行时究竟是如何将一个个Goroutine调度到CPU上执行的。当然,Goroutine的调度本来是Go语言核心开发团队才应该关注的事情,大多数Gopher们无需关心。但就我个人的学习和实践经验而言,我觉... 查看详情

goroutine并发调度模型深度解析之手撸一个协程池(代码片段)

golanggoroutine协程池GroutinePool高并发并发(并行),一直以来都是一个编程语言里的核心主题之一,也是被开发者关注最多的话题;Go语言作为一个出道以来就自带『高并发』光环的富二代编程语言,它的并发(并行)编程肯定是... 查看详情

go36-16,17-goroutine(代码片段)

...讯的方式共享数据。更具体地说,它一般被用来在不同的goroutine之间传递数据。这篇主要讲goroutine是什么。简单来说,goroutine代表着并发编程模型中的用户级线程。调度器Go语言不但有着独特的并发编程模型,以及用户级线程goro... 查看详情

goroutine

进程和线程进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程可以创建和撤销多个... 查看详情

19.go语言基础之并发(代码片段)

...windows中360在杀毒,同时你也在写代码)Go语言的并发通过goroutine实现。goroutine类似于线程,属于用户态的线程,我们可以根据需要创建成千上万个goroutine并发工作。goroutine是由Go语言的运行时(runtime)调度完成,而线程是由操作系... 查看详情

go的调度与go的gc

go的调度与go的GC调度首先golang的goroutine占用的资源非常小,默认size是2k,goroutine调度的切换也不用到内核层去完成,代价很低,所以go可以创建成千上万个goroutine。对于操作系统而言,go程序是一个用户层程序,对goroutine是不可... 查看详情

go高阶:调度器gmp原理与调度全分析(代码片段)

...代有了调度器需求(3)协程来提高CPU利用率(4)Go语言的协程goroutine(5)被废弃的goroutine调度器二、Goroutine调度器的GMP模型的设计思想(1)GMP模型(2)调度器的设计策略(3)gofunc()调度流程( 查看详情

golang---gmp调度策略(代码片段)

...今天我们来学习Go的调度机制。数据结构G结构体 G是goroutine的缩写,相当于操作系统中的进程控制块,在这里就是goroutine的控制结构,是对goroutine的抽象,下面是G的结构(只列出了部分与调度有关的)://用于保存上下文的gobuf... 查看详情