当前位置: 首页 > article >正文

【Golang 面试题】每日 3 题(五十七)

✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/UWz06
📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

169. 协作式的抢占式调度

在 Go 语言中,Goroutine 调度器采用的是协作式调度,也就是说,在一个 Goroutine 执行过程中,如果没有主动交出控制权(比如调用 time.Sleep()、channel 操作等),其他 Goroutine 是无法抢占执行的。这样可以避免出现线程安全的问题,但也会导致某个 Goroutine 长时间占用 CPU 时间,从而降低程序整体的并发性能。

为了解决这个问题,Go 语言在 1.14 版本引入了抢占式调度。抢占式调度的主要思想是,在 Goroutine 执行过程中,如果某个 Goroutine 执行时间过长,会被强制抢占,让其他 Goroutine 有机会执行。这样可以保证所有 Goroutine 公平地获得 CPU 时间,从而提高程序的并发性能。

在抢占式调度中,Go 语言采用了基于信号的抢占方式。具体来说,当一个 Goroutine 执行时间过长时,会在指定时间内收到一个抢占信号,然后在信号处理程序中暂停当前 Goroutine 的执行,并将控制权交给调度器,让调度器决定下一个要执行的 Goroutine。当下一个 Goroutine 开始执行时,之前被暂停的 Goroutine 就被称为 “被抢占” 的 Goroutine。

需要注意的是,抢占式调度只在 Go 语言的系统线程中生效,而在非系统线程中,仍然采用协作式调度。这是因为非系统线程是由 Go 语言运行时管理的,无法被操作系统直接抢占,因此只能采用协作式调度。另外,抢占式调度对于需要实现低延迟的应用程序可能不太适合,因为抢占操作需要额外的 CPU 时间,从而增加了系统的响应时间。

170. 协作式的抢占式调度如何实现?

下面是一个简单的抢占式调度的示例代码:

package main
import (
        "fmt"
        "time"
)
func main() {
        go func() {
                for {
                        fmt.Println("Goroutine 1 is running")
                        time.Sleep(time.Second)
                }
        }()
        go func() {
                for {
                        fmt.Println("Goroutine 2 is running")
                        time.Sleep(time.Second)
                }
        }()
        for {
                fmt.Println("Main Goroutine is running")
                time.Sleep(time.Second)
        }
}

在这个示例代码中,我们定义了三个 Goroutine,分别是 “Goroutine 1”、“Goroutine 2” 和 “Main Goroutine”。其中,“Goroutine 1” 和 “Goroutine 2” 分别每秒输出一次自己的名称,而 “Main Goroutine” 每秒输出一次自己的名称。

我们可以运行这个程序并观察输出结果。在协作式调度下,我们会发现 “Main Goroutine” 总是先输出,而 “Goroutine 1” 和 “Goroutine 2” 则交替输出。而在抢占式调度下,由于 Goroutine 执行时间被限制,我们会发现 “Main Goroutine”、“Goroutine 1” 和 “Goroutine 2” 三个 Goroutine 的输出基本上是随机的,每个 Goroutine 每秒只能输出一次。

需要注意的是,抢占式调度并不是默认启用的,如果要启用抢占式调度,可以通过设置 GOMAXPROCS 环境变量或调用 runtime.GOMAXPROCS() 函数来指定使用的系统线程数。当 GOMAXPROCS 的值大于 1 时,Go 语言会自动启用抢占式调度。

171. 基于信号的抢占式调度

在 golang 中,除了协作式调度和抢占式调度,还有一种基于信号的抢占式调度。基于信号的抢占式调度可以让 Goroutine 在执行过程中被立即中断,并强制切换到其他 Goroutine,从而实现抢占式调度。

在 golang 中,我们可以使用 runtime 包中的两个函数实现基于信号的抢占式调度:

  • runtime.Gosched():让出 CPU 时间片,让其他 Goroutine 运行。
  • runtime.LockOSThread():将当前 Goroutine 绑定到当前线程上,让该 Goroutine 独占一个线程,从而实现更精细的调度控制。

http://www.kler.cn/a/553517.html

相关文章:

  • “深入浅出”系列之杂谈篇:(3)Qt5和Qt6该学哪个?
  • 常用 Webpack Plugin 汇总
  • LangChain大模型应用开发:消息管理与聊天历史存储
  • 单细胞转录组画小提琴VlnPlot只显示需要类型细胞
  • 【Linux】文件系统:文件fd
  • Android系统开发 给system/app传包报错
  • 清华大学DeepSeek PPT第二版 Deepseek赋能职场应用
  • 1、云原生写在前面
  • 部署前端项目
  • Docker 容器安装 Dify的两种方法
  • windows Redis Insight 如何查看宝塔docker里的redis数据
  • 【Python】集合set详细讲解(语法、操作、集合运算、性能、使用场景)
  • Luckfox Pico Max运行RKNN-Toolkit2中的Yolov5 adb USB仿真
  • 算法练习——前缀和
  • jdk从1.7升级为1.8需要注意什么
  • SOME/IP--协议英文原文讲解8
  • nginx ngx_http_module(7) 指令详解
  • Java 面试笔记 - Java基础
  • 【拥抱AI】GPT Researcher的诞生
  • 基于SpringBoot的小区运动中心预约管理系统