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

深入理解 Go 并发原语

1. goroutine 基础知识

1.1 进程

        进程(process) 是一个程序的实例,具有某些专用资源,如内存空间、处理器时间、文件句柄(例如,Linux 中的大多数进程都有 stdin、stdout 和 stderr) 和至少一个线程。我们称其为实例(instance),这是因为同一个进程可以用来创建多个进程。

        在大多数通用操作系统中,每个进程都与其他进程隔离,因此任何两个希望通信实用程序来完成。

        当进程终止时,为该进程分配的所有内存都将被释放,所有打开的文件都将被关闭,并且所有线程都将被终止。

1.2 线程

        线程( thread ) 是一个执行上下文,包含运行指令序列所需的所有资源。通常,它包含堆栈和处理器寄存器的值。堆栈对于保持该线程内嵌套函数调用的顺序以及存储在该线程中执行的函数中声明的值是必需的。一个给定的函数可能在许多不同的线程中执行,因此该函数在线程中运行时使用的局部变量将存储在该线程的堆栈中。

1.3 调度程序

        调度程序 (scheduler) 可以将处理器时间分配给线程。有些调度程序是抢占式的,可以随时停止一个线程以切换到另一个线程。有些调度程序是协作的,必须等待线程才能切换到另一个线程。线程通常由操作系统管理。

1.4 goroutine 

        goroutine 是由 Go 运行时管理的执行上下文(而不是由操作系统管理的线程)。goroutine 的启动开销通常比操作系统线程小得多。

        goroutine 从一个小堆栈开始,并根据需要进行增长。创建新的 goroutine 比创建操作系统线程更快、更便宜。Go 调度程序将分配操作系统线程来运行 goroutine。

在 Go 程序中, goroutine 是使用 go 关键字创建的,后跟函数调用:

go f()
go g(i,j)
go func(){...
}()
go func(i,j int) {...
}(1,2)

         go 关键字在新的 goroutiine 中启动给定的函数。现有的 goroutine 继续与新创建的 goroutine 并发运行。

        作为 goroutine 运行的函数可以接收参数,但不能返回值。goroutine 函数的参数在 goroutine 启动之前进行评估,并在 goroutine 开始运行时传递给函数。

        你可能会问,为什么需要开发一个全新的线程系统,只是为了获得轻量级线程?

        goroutine 不仅仅是轻量级线程。它们是通过在准备运行的 goroutine 之间有效共享处理能力来提高吞吐量的关键。这是该思想的要点。

        Go 运行时使用的操作系统线程数等于平台上的处理器/内核数(除非你通过设置 GOMAXPROCS 环境变量或调用 runtime.GOMAXPROCS 函数来更改此设置)。这是平台可以并行执行的操作数量。除些之外,操作系统将不得不求助于分时系统。

        由于 GOMAXPROCS 线程并行运行,因此操作系统级别没有上下文切换开销。Go 调度程序将 goroutine 分配给操作系统线程,以便在每个线程上完成更多工作,而不是在许多线程上完成更少的工作。

        较小的上下文切换并不是 Go 调度程序比操作系统调度程序性能更好的唯一原因。 Go 调度程序之所以表现更好,是因为它知道唤醒哪些 goroutine 以充分利用它们。操作系统不知道通道操作或互斥体,这两种操作都是由 Go 运行时在用户空间中管理的。

1.5 线程和 goroutine 之间的区别

        除了 goroutine 更为轻量级,线程和 goroutine 之间还有一些更细微的区别。

        线程通常具有优先级。当优先级线程与高优先级线程竞争共享资源时,高优先级线程有更好的机会获得共享资源。

        goroutine 没有预先分配的优先级。也就是说,该语言规范允许有一个有利于某些 goroutine 的调度程序。例始, Go 运行时的更高版本包括将选择饥饿 goroutine 的调度算法。

        不过,一般来说,正确的并发 Go 程序不应该依赖于调度行为。许多语言都具有诸如使用可配置调度算法的线程池之类的功能。这些功能是基于 “线程创建是一项昂贵的操作” 这一假设而开发的,而 Go 的情况并非如此。

        另一个区别是 goroutine 堆栈的管理方式。一个 goroutine 以一个小堆栈开始(1.19 之后的 Go 运行时使用历史平均值,早期版本使用 2KB),每个函数调用都会检查剩余的堆栈空间是否足够。如果不足,则调整堆栈大小。

        反观操作系统线程则通常以一个大得多的堆栈(以兆字节为单位)开始,并且该堆栈通常不会增长。

http://www.lryc.cn/news/427443.html

相关文章:

  • 计算机毕业设计选题推荐-springboot 基于springboot的宠物健康顾问系统
  • 数据结构—— 初识二叉树
  • 2024.08.09校招 实习 内推 面经
  • IDEA中设置类和方法的注释
  • Adobe Premiere Pro 2023-23.6.7.1 解锁版下载与安装教程 (一款专业的视频编辑软件)
  • openGauss 6.0安装过程解除对root用户依赖之gs_preinstall
  • IOS 10 统一颜色管理和适配深色模式
  • Linux目录结构及基础查看命令和命令模式
  • UDP和TCP协议段格式分析
  • Go语言基础--条件判断(if语句)
  • 白骑士的C#教学实战项目篇 4.2 图形用户界面(GUI)应用
  • 【Java学习】反射和枚举详解
  • leetcode-461. 汉明距离
  • rpmbuild 将二进制文件 strip,文件 md5 发生改变
  • selenium爬取搜狗网站新闻的小Demo
  • R 语言学习教程,从入门到精通,R CSV 文件使用(17)
  • 【LLM之Base Model】Weaver论文阅读笔记
  • 泰坦尼克号 - 从灾难中学习机器学习/Titanic - Machine Learning from Disaster(kaggle竞赛)第一集(了解赛题)
  • 使用C++调用PyTorch模型的弯弯绕绕,推荐LibTorch加载,C++处理
  • 实现异形(拱形)轮播图
  • 【软件测试】2024年职业院校技能大赛高职组“软件测试”赛项样题
  • python数组和队列
  • Vision Transformer(ViT)一种将Transformer架构应用于计算机视觉领域的模型
  • 得到任务式 大模型应用开发学习方案
  • 使用el-menu跳转时偶尔会出现路由已经变了,但是页面却显示空白的情况
  • C语言家教记录(七)
  • 【数据结构】——十大排序详解分析及对比
  • 散点图适用于什么数据 thinkcell散点图设置不同颜色
  • 1. windows搭建Kafka教程
  • XSS复现