0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

详解剖析Go语言调度模型的设计

马哥Linux运维 来源:爱户外的程序猿 作者:爱户外的程序猿 2021-07-26 10:12 次阅读

golang的MPG调度模型是保障Go语言效率高的一个重要特性,本文详细介绍了Go语言调度模型的设计。

前言

Please remember that at the end of the day, all programs that work on UNIX machines end up using C system calls to communicate with the UNIX kernel and perform most of their tasks. 所有在 UNIX 系统上运行的程序最终都会通过 C 系统调用来和内核打交道。

用其他语言编写程序进行系统调用,方法不外乎两个:一是自己封装,二是依赖 glibc、或者其他的运行库。Go 语言选择了前者,把系统调用都封装到了 syscall 包。封装时也同样得通过汇编实现。

异步系统调用 G 会和MP分离(G挂到netpoller),同步系统调用 GM 会和P分离(P另寻M),生动的说明了GPM相对GM的精妙之处。

阻塞

在 Go 里面阻塞主要分为以下 4 种场景:

由于原子、互斥量或通道操作调用导致 Goroutine 阻塞,调度器将把当前阻塞的 Goroutine 切换出去,重新调度 LRQ 上的其他 Goroutine;

由于网络请求和 IO 操作导致 Goroutine 阻塞。Go 程序提供了网络轮询器(NetPoller)来处理网络请求和 IO 操作的问题,其后台通过 kqueue(MacOS),epoll(Linux)或 iocp(Windows)来实现 IO 多路复用。通过使用 NetPoller 进行网络系统调用,调度器可以防止 Goroutine 在进行这些系统调用时阻塞 M。

这可以让 M 执行 P 的 LRQ 中其他的 Goroutines,而不需要创建新的 M。执行网络系统调用不需要额外的 M,网络轮询器使用系统线程,它时刻处理一个有效的事件循环,有助于减少操作系统上的调度负载。

用户层眼中看到的 Goroutine 中的“block socket”,实现了 goroutine-per-connection 简单的网络编程模式。实际上是通过 Go runtime 中的 netpoller 通过 Non-block socket + I/O 多路复用机制“模拟”出来的。

当调用一些系统方法的时候(如文件 I/O),如果系统方法调用的时候发生阻塞,这种情况下,网络轮询器(NetPoller)无法使用,而进行系统调用的 G1 将阻塞当前 M1。调度器引入 其它M 来服务 M1 的P。

如果在 Goroutine 去执行一个 sleep 操作,导致 M 被阻塞了。Go 程序后台有一个监控线程 sysmon,它监控那些长时间运行的 G 任务然后设置可以强占的标识符,别的 Goroutine 就可以抢先进来执行。

系统调用

Go 语言通过 Syscall 和 Rawsyscall 等使用汇编语言编写的方法封装了操作系统提供的所有系统调用,其中 Syscall 在 Linux 386 上的实现如下:

TEXT ·Syscall(SB),NOSPLIT,$0-28

CALL runtime·entersyscall(SB)

MOVL trap+0(FP), AX // syscall entry

MOVL a1+4(FP), BX

MOVL a2+8(FP), CX

MOVL a3+12(FP), DX

MOVL $0, SI

MOVL $0, DI

INVOKE_SYSCALL

CMPL AX, $0xfffff001

JLS ok

MOVL $-1, r1+16(FP)

MOVL $0, r2+20(FP)

NEGL AX

MOVL AX, err+24(FP)

CALL runtime·exitsyscall(SB)

RET

ok:

MOVL AX, r1+16(FP)

MOVL DX, r2+20(FP)

MOVL $0, err+24(FP)

CALL runtime·exitsyscall(SB)

RET

Golang - 调度剖析 https://segmentfault.com/a/1190000016611742

Go: Goroutine, OS Thread and CPU Management https://medium.com/a-journey-with-go/go-goroutine-os-thread-and-cpu-management-2f5a5eaf518a

Go optimizes the system calls — whatever it is blocking or not — by wrapping them up in the runtime. This wrapper will automatically dissociate the P from the thread M and allow another thread to run on it.

异步系统调用

通过使用网络轮询器进行网络系统调用,调度器可以防止 Goroutine 在进行这些系统调用时阻塞M。这可以让M执行P的 LRQ 中其他的 Goroutines,而不需要创建新的M。有助于减少操作系统上的调度负载。

G1正在M上执行,还有 3 个 Goroutine 在 LRQ 上等待执行

接下来,G1想要进行网络系统调用,因此它被移动到网络轮询器并且处理异步网络系统调用。然后,M可以从 LRQ 执行另外的 Goroutine。

最后:异步网络系统调用由网络轮询器完成,G1被移回到P的 LRQ 中。一旦G1可以在M上进行上下文切换,它负责的 Go 相关代码就可以再次执行。

同步系统调用

G1将进行同步系统调用以阻塞M1

调度器介入后:识别出G1已导致M1阻塞,此时,调度器将M1与P分离,同时也将G1带走。然后调度器引入新的M2来服务P。

b030aa1a-db82-11eb-9e57-12bb97331649.png

阻塞的系统调用完成后:G1可以移回 LRQ 并再次由P执行。如果这种情况需要再次发生,M1将被放在旁边以备将来使用。

b03e4c56-db82-11eb-9e57-12bb97331649.png

sysmon 协程

b04936ca-db82-11eb-9e57-12bb97331649.jpg

在 linux 内核中有一些执行定时任务的线程, 比如定时写回脏页的 pdflush, 定期回收内存的 kswapd0, 以及每个 cpu 上都有一个负责负载均衡的 migration 线程等。在 go 运行时中也有类似的协程 sysmon. sysmon 运行在 M,且不需要 P。它会每隔一段时间检查 Go 语言runtime,确保程序没有进入异常状态。

系统监控的触发时间就会稳定在 10ms,功能比较多:

检查死锁runtime.checkdead

运行计时器 — 获取下一个需要被触发的计时器;

定时从 netpoll 中获取 ready 的协程

Go 的抢占式调度

当 sysmon 发现 M 已运行同一个 G(Goroutine)10ms 以上时,它会将该 G 的内部参数 preempt 设置为 true。然后,在函数序言中,当 G 进行函数调用时,G 会检查自己的 preempt 标志,如果它为 true,则它将自己与 M 分离并推入“全局队列”。由于它的工作方式(函数调用触发),在 for{} 的情况下并不会发生抢占,如果没有函数调用,即使设置了抢占标志,也不会进行该标志的检查。

Go1.14 引入抢占式调度(使用信号的异步抢占机制),sysmon 仍然会检测到运行了 10ms 以上的 G(goroutine)。然后,sysmon 向运行 G 的 P 发送信号(SIGURG)。Go 的信号处理程序会调用P上的一个叫作 gsignal 的 goroutine 来处理该信号,将其映射到 M 而不是 G,并使其检查该信号。gsignal 看到抢占信号,停止正在运行的 G。

在满足条件时触发垃圾收集回收内存;

打印调度信息,归还内存等定时任务。

转自:bert.li@ximalaya.com

qiankunli.github.io/2020/11/21/goroutine_system_call.html

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • go语言
    +关注

    关注

    1

    文章

    155

    浏览量

    8913

原文标题:Golang 系统调用与阻塞处理

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    使用go语言实现一个grpc拦截器

    在开发grpc服务时,我们经常会遇到一些通用的需求,比如:日志、链路追踪、鉴权等。这些需求可以通过grpc拦截器来实现。本文使用go语言来实现一个 grpc一元模式(Unary)拦截器,上报链路追踪信息。
    的头像 发表于 12-18 10:13 200次阅读
    使用<b class='flag-5'>go</b><b class='flag-5'>语言</b>实现一个grpc拦截器

    Go编程语言-你应该知道的一切

    Go 编程语言的故事始于 Google,当时三位工程师 Robert Griesemer、Rob Pike 和 Ken Thompson 对 C++ 的复杂性以及缺乏提供高效编译和执行的简单语言感到厌倦。
    的头像 发表于 12-11 17:37 270次阅读

    语言模型简介:基于大语言模型模型全家桶Amazon Bedrock

    本文基于亚马逊云科技推出的大语言模型与生成式AI的全家桶:Bedrock对大语言模型进行介绍。大语言模型
    的头像 发表于 12-04 15:51 365次阅读

    Go语言比Python强多少

    1.都说Go语言性能非常强大,那么到底比Python强多少? 为了比较Go语言和Python语言在单线程性能上的差距,我们可以做一个简单实验
    的头像 发表于 11-02 14:05 254次阅读
    <b class='flag-5'>Go</b><b class='flag-5'>语言</b>比Python强多少

    如何让Python和Go互相调度

    我们曾经研究过如何让Python和Go互相调度,当时发现,将Go语言写的模块打包成动态链接库,就能在Python中进行调度: 优劣互补! P
    的头像 发表于 11-02 11:24 225次阅读
    如何让Python和<b class='flag-5'>Go</b>互相<b class='flag-5'>调度</b>

    腾讯发布混元大语言模型

    腾讯发布混元大语言模型 腾讯全球数字生态大会上腾讯正式发布了混元大语言模型,参数规模超千亿,预训练语料超2万亿tokens。 作为腾讯自研的通用大
    的头像 发表于 09-07 10:23 822次阅读

    检索增强的语言模型方法的详细剖析

      本篇内容是对于ACL‘23会议上陈丹琦团队带来的Tutorial所进行的学习记录,以此从问题设置、架构、应用、挑战等角度全面了解检索增强的语言模型,作为对后续工作的准备与入门,也希望能给大家带来
    的头像 发表于 08-21 09:58 1242次阅读
    检索增强的<b class='flag-5'>语言</b><b class='flag-5'>模型</b>方法的详细<b class='flag-5'>剖析</b>

    Go语言中的整数类型

    Go 语言中,整型可以细分成两个种类十个类型。
    发表于 07-20 15:25 285次阅读

    Go语言常量的声明

    Go 语言中, 常量 表示的是固定的值,常量表达式的值在编译期进行计算,常量的值不可以修改。例如:3 、 Let's go 、 3.14 等等。常量中的数据类型只可以是 布尔型 、 数字型 (整数型、浮点型和复数)
    发表于 07-20 15:24 263次阅读

    Go语言简介和安装方法

    Go 又称 Golang ,是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言Go 语言语法与
    发表于 07-19 16:33 396次阅读

    语言模型的发展历程 基于神经网络的语言模型解析

    简单来说,语言模型能够以某种方式生成文本。它的应用十分广泛,例如,可以用语言模型进行情感分析、标记有害内容、回答问题、概述文档等等。但理论上,语言
    发表于 07-14 11:45 464次阅读
    <b class='flag-5'>语言</b><b class='flag-5'>模型</b>的发展历程 基于神经网络的<b class='flag-5'>语言</b><b class='flag-5'>模型</b>解析

    SystemVerilog里的regions以及events的调度

    本文讲一下SystemVerilog的time slot里的regions以及events的调度。SystemVerilog语言是根据离散事件执行模型定义的,由events驱动。
    的头像 发表于 07-12 11:20 790次阅读
    SystemVerilog里的regions以及events的<b class='flag-5'>调度</b>

    浅谈SylixOS 实时操作系统中Go语言应用

    Go 语言是一门编译型语言,继承了编译型语言的高性能、类型安全以及对计算机底层的高可控性等特点,其运行性能可与C/C++媲美。Go
    发表于 06-08 10:41 747次阅读
    浅谈SylixOS 实时操作系统中<b class='flag-5'>Go</b><b class='flag-5'>语言</b>应用

    Go语言运算符主要包括哪些呢?

    Go语言运算符主要包括:算数运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和其他运算符。
    的头像 发表于 05-26 15:54 575次阅读
    <b class='flag-5'>Go</b><b class='flag-5'>语言</b>运算符主要包括哪些呢?

    Go语言中的包

    每个 Go 文件都属于且仅属于一个包,一个包可以由许多以 .go 为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。
    的头像 发表于 04-17 09:22 1086次阅读