Go--协程

news2024/10/2 22:19:20

协程

协程是Go语言最大的特色之一。

1、协程的概念

协程并不是Go发明的概念,支持协程的变成语言有很多。Go在语言层面直接提供对协程的支持称为goroutine。

1.1 基本概念
  1. 进程

    进程是应用程序启动的实例,每个进程都有独立的内存空间,不同进程之前通过进程间的通信方式实现。

  2. 线程

    线程从属于进程,每个进程至少包含一个线程,线程是CPU调度的基本单位,多个线程之间可以共享进程的资源并通过共享内存等线程间的通信方式来通信。

  3. 协程

    协程可以理解为一种轻量级线程,与线程相比,协程不受操作系统调度,协程调度器由用户应用程序提供,协程调度器按照调度策略把协程调度到线程中运行。Go应用程序得到协程调度器由runtime包提供,用户使用go关键字即可创建协程。

1.2 协程的优势

​ 在高并发应用中频繁的创建线程会造成不必要的开销,所以有了线程池技术。在线程池中预先保存一定数量的线程,新任务将不再以创建线程的方式去执行,而是将任务发布到任务队列中,线程池中的线程不断地从任务队列中取出任务并执行,这样可以有效地减少线程的创建和销毁带来的开销。

​ 下图展示了一个典型的线程池:
在这里插入图片描述

​ 我们把任务队列中的每个任务称作G,而G往往代表一个函数。线程池中的worker线程不断地从任务队列中取出任务并执行,而worker线程则交给操作系统进行调度。

​ 如果worker线程执行的G任务中发生系统调用,则操控系统会将线程置为阻塞状态,也就意味着该线程在怠工,由于消费任务队列中的worker线程变少了,所以线程池消费任务队列的能力变弱了。

​ 如果任务队列中的大部分任务都进行系统调用,则会让这种状态恶化,大部分worker线程进入阻塞状态,从而任务队列中的任务产生堆积。

​ 解决这个问题的一个思路是重新审视线程池中线程的数量,增加线程池中的线程数量,以在一定程度上提高消费力,但随着线程数量增多,过多线程争抢CPU资源,消费能力会有上限,甚至出现消费能力下降的现象,如下图所示。

在这里插入图片描述

​ 过多的线程会导致上下文切换的开销变大,而工作在用户态的协程能大大减少上下文切换的开销。协程调度器把可运行的协程逐个调度到线程中执行,同时及时把阻塞的协程调度出协程,从而有效地避免了线程的频繁切换,达到了使用少量线程实现高并发地效果。

​ 多个协程分享操作系统分给线程的时间片,从而达到充分利用CPU算力的目的,协程调度器则决定了协程执行的顺序。

2、调度模式
2.1 线程模型

​ 线程可分为用户线程和内核线程,用户线程由用户创建、同步和销毁,内核线程则由内核来管理。根据用户线程管理方式的不同,分为三种线程模型。

  • N : 1模型,由N个用户线程运行在1个内核线程中,优点是用户线程上下文切换快,缺点是无法充分利用CPU多核的算力。
  • 1 : 1模型,即每个用户线程对应一个内核线程,优点是充分利用CPU的算力,缺点是线程上下文切换慢。
  • Go实现的是 M : N模型,M个用户线程(协程)运行在N个线程中,优点是充分利用CPU的算力且协程上下文切换快,缺点则是该模型的调度算法较为复杂。
2.2 Go调度器模型

​ Go协程调度模型中包含三个关键实体,machine(简称M)、processor(简称P)和 goroutine (简称G)。

  • M:工作线程,由操作系统调度。
  • P:处理器(G0定义的一个概念,不是指CPU),包含运行Go代码的必要资源,也有调度goroutine的能力。
  • G:即Go协程,每个Go关键字都会创建一个协程。

​ M必须持有P才可以执行代码,跟系统中的其他线程一样,M也会被系统调用阻塞。P的个数在程序启动时决定,默认情况下等同于CPU的核数,可以使用环境变量 GOMAXPROCS 或在程序中使用runtime.GOMAXPROCS()犯法指定P的个数。

​ M的个数通常稍大于P的个数,因为除了运行Go代码,runtime包还有其他内置任务需要处理。一个简单的调度器模型如下图所示。

在这里插入图片描述

​ 上图中包括两个工作线程M,每个M持有一个处理器P,并且每个M中有一个绿色背景的协程G在运行。其余的协程正在等待被调用,它们位于被称为runqueues的队列中。每个处理器P中拥有一个runqueues队列,此外还有一个全局的runqueues队列,由多个处理器共享。

​ 早期的调度器实现中(Go1.1之前)只包含全局的runqueues,多个处理器P通过互斥锁来调度队列中的线程,在多个CPU或多核环境中,多个处理器需要经常争抢锁来调度全局队列中的协程,严重影响了并发执行效率。后来便引入了局部runqueues,每个处理器P访问自己的runqueues时不需要加锁,大大提高了效率。

​ 一般来说,处理器P中的协程G额外再创建的协程会加入本地的runqueues中,但如果本地的队列已满,或者阻塞的协程被唤醒,则协程会被放入全局的runqueues中,处理器P除了调度本地的runqueues中的协程,还会周期性地从全局runqueues中摘取协程来调度。

3、调度策略
3.1 队列轮转

​ 每个处理器P维护着一个协程G的队列,处理器P依次将协程G调度到M中执行。同时每个P会周期性地查看全局队列中是否有G待运行并将其调度到M中执行,全局队列中的G主要来自从系统调用中恢复的G。

3.2 系统调用

​ 当线程在执行系统调用时,可能会阻塞,对应到调度器模型,如果一个协程发起系统调用,那么对应的工作线程会被阻塞,这样一来,处理器P的runqueues队列中的协程将得不到调用,相对于队列中的所有协程都被阻塞

​ 前面提到P的个数默认等于CPU的核数,每个M必须持有一个P才可以执行G。一般情况下M的个数略大于P的个数,多出来的M将会在G产生系统调用时发挥作用。与线程池类似,Go也提供一个M的池子,需要时从池子中获取,用完放回池子,不够时就再创建一个。

​ 当M运行的某个G产生系统调用时,过程如下图所示。

在这里插入图片描述

​ 当Go即将进入系统调用时,M0将释放P,进而某个冗余的M1获取P,继续执行P队列中剩下的G。M0由于陷入系统调用而被阻塞,M1接管M0的工作,只要P不空闲,就可以保证充分利用CPU。

​ 冗余的M的来源有可能是缓存池,也可能是新建的。当Go结束系统调用后,根据M0是否能获取到P,对G0进行不同的处理:

  • 如果有空闲的P,则获取一个P,继续执行G0。
  • 如果没有空闲的P,则将G0放入全局队列,等待被其他的P调度。然后M0将进入缓存池休眠。
3.3 工作量切取

​ 通过go关键字创建的协程通常会优先放到当前协程对应的处理器队列中,可能有些协程自身不断地派生出新的协程,而有些协程不派生协程。如此一来,多个处理器P中维护地G队列有可能是不均衡的,如果不加以控制,则有可能出现部分处理器P非常繁忙,而部分处理器怠工的情况。

​ 为此,Go调度器提供了工作量切取策略,当某个处理器P没有需要调度的协程时,将从其他处理器中切取协程。

在这里插入图片描述

​ 发生切取前右侧的处理器P在没有协程需要调度时会查询全局队列,如果全局队列中也没有协程需要调度,则会从另一个正在运行的处理器P中偷取协程,每次偷取一半。

3.4 抢占式调度

​ 调度器会监控每个协程的执行时间,一旦执行时间过长且有其他协程在等待时,会把协程暂停,转而调度等待的协程,以达到类似于时间片轮转的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1293552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DSP外部中断笔记

中断原理 三部分 注意 ,外部中断使能,PIE使能,CPU中断使能 外部中断有7个,PIE有12组,一个组有8个中断复用。只有一个CPU中断可执行。 外部中断原理 1、外部中断概述 外部中断结构图 外部中断XINT1对应的是0到31GPI…

<IBM Websphere Portal>《关于IBM的Portal和WAS的说明和总结(自用笔记)》

《关于IBM的Portal和WAS的简单总结》 1 架构1.1 说明 2 常见问题2.1 LDAP链接问题2.2 启动脚本建议2.3 日志大小保留建议2.4 启动垃圾回收日志 3 日志位置 1 架构 应用服务部署架构如上: 👉192.168.66.1服务器运行的server进程有:dmgr、nodea…

360压缩安装一半不动了怎么办?

360压缩软件是我们常用的压缩软件,但是常常会遇到压缩安装到一半停止的情况,下面提供了一些可能的原因和解决办法,大家可以进行尝试~ 方法一:关闭防火墙和杀毒软件 有时候,防火墙和杀毒软件可能会阻止360压缩的安装过…

为什么 SQL 不适合图数据库

背景 “为什么你们的图形产品不支持 SQL 或类似 SQL 的查询语言?” 过去,我们的一些客户经常问这个问题,但随着时间的推移,这个问题变得越来越少。 尽管一度被忽视,但图数据库拥有无缝设计并适应其底层数据结构的查询…

Docker实战笔记 二 Springboot Idea 插件打包

1.上传springboot的jar rootcenots-7.5:/home/code#rz -----app.jar 2.编辑Dockerfile rootcenots-7.5:/home/code#vi Dockerfile内容 FROM openjdk:8 # 作者 MAINTAINER nnd # 声明要使用的端口 EXPOSE 8080 # VOLUME 指定了临时文件目录为/tmp。# 将本地包添加到容器中并…

服装收银系统哪个最好用

服装订货系统哪个最好,可能没有一个标准的答案,但至少可以从以下几点进行选择: 1、数据批量操作:服装到货都是一批一批,如果能将条码进行批量导入,这样在这里耗去的时间就少很多了,剩下的是时间…

在Windows 11中更改文件的扩展名有几种办法,个别办法可以批量修改

本文介绍了如何在Windows 11中更改文件的文件扩展名。 用简单的方法更改文件扩展名 对于大多数人来说,在Windows 11中更改文件扩展名的最简单方法是在更改文件名的同一个地方进行更改。然而,Windows默认情况下不显示文件扩展名,所以在我们可…

【Flink系列三】数据流图和任务链计算方式

上文介绍了如何计算并行度和slot的数量,本文介绍Flink代码提交后,如何生成计算的DAG数据流图。 程序和数据流图 所有的Flink程序都是由三部分组成的:Source、Transformation和Sink。Source负责读取数据源,Transformation利用各种…

西南科技大学C++程序设计实验八(多态一)

一、实验目的 1. 掌握多态性的分类; 2. 动态多态性-虚函数; 3. 理解纯虚函数的概念。 二、实验任务 1.分析以下程序,改正程序错误,写出程序输出结果,并按要求: (1)思考:输出结果中为什么类A是8个字节,类B是12个字节?分析虚函数的类的结构特点 A的字节大小为:…

基于JAVA+SpringBoot+微信小程序的宠物领养平台

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 随着人们生活水平的提…

VS2015编译GDAL3.2.0+opencl+C#

参考借鉴https://www.cnblogs.com/litou/p/15004877.html 参考借鉴https://www.cnblogs.com/xiaowangba/p/6313903.html 参考借鉴gdal、proj、geos、sqlite等在VS2015下编译和配置_vs2015编译sqlite3-CSDN博客 参考借鉴Windows下GDAL3.1.2编译 (VS2015)_gdal windows编译-CS…

Spring Boot HTTP 400 错误的日志信息在哪里查看 ?

HTTP 400 一般来说是入参的某些字段的格式不对 Spring Boot项目启动后默认是不会把相应的日志打印在控制台的 需要在logback.xml里面做相关的配置才会打印出来 具体配置如下 <configuration><appender name"stdout" class"ch.qos.logback.core.Con…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux文件管理(3)》(27)

《Linux操作系统原理分析之Linux文件管理&#xff08;3&#xff09;》&#xff08;27&#xff09; 8 Linux文件管理8.6 文件管理和操作8.6.1 系统对文件的管理8.6.2 进程对文件的管理 8 Linux文件管理 8.6 文件管理和操作 8.6.1 系统对文件的管理 Linux 系统把所有打开的活动…

Agility Robotics 为亚马逊仓库批量生产的人形机器人

一家旨在每年生产 10000 个两足机器人的革命性工厂即将在俄勒冈州塞勒姆成形。 这些机器人由 Agility Robotics 开发&#xff0c;旨在协助亚马逊等行业巨头运输、起重和处理危险货物。 Agility Robotics 表示&#xff0c;其名为 RoboFab 的新制造工厂将成为世界上第一个大规模…

正则表达式详细讲解

目录 一、正则表达式概念 二、八元素 1、普通字符&#xff1a; 2、元字符&#xff1a; 3、通配符 .&#xff1a; 4、字符类 []&#xff1a; 5、量词&#xff1a; 6、锚点 ^ 和 $&#xff1a; 7、捕获组 ()&#xff1a; 8、转义字符 \&#xff1a; 三、日常使用的正则…

iOS(swiftui)——系统悬浮窗( 可在其他应用上显示,可实时更新内容)

因为ios系统对权限的限制是比较严格的,ios系统本身是不支持全局悬浮窗(可在其他app上显示)。在iphone14及之后的iPhone机型中提供了一个叫 灵动岛的功能,可以在手机上方可以添加一个悬浮窗显示内容并实时更新,但这个功能有很多局限性 如:需要iPhone14及之后的机型且系统…

【Lidar】基于Python的三维点云数据转二维平面+散点图绘制

最近一直在搞点云相关的操作&#xff0c;有时候在处理点云数据时需要查看处理后的数据是否满足需求&#xff0c;所以就想着写一套展示点云的代码。之前已经分享过如何可视化点云了&#xff0c;感兴趣的可以自己去看下&#xff1a;【Lidar】基于Python的Open3D库可视化点云数据。…

css 元素前后添加图标(::before 和 ::after 的妙用)

<template><div class"container"><div class"label">猜你喜欢</div></div> </template><style lang"scss" scoped> .label {display: flex;&::before,&::after {content: "";widt…

Leetcode—290.单词规律【简单】

2023每日刷题&#xff08;五十一&#xff09; Leetcode—290.单词规律 实现代码 class Solution { public:bool wordPattern(string pattern, string s) {unordered_map<char, string> m1;unordered_map<string, char> m2;stringstream stro(s);string tmp;for(a…

Anisble中剧本的应用

1.什么是playbook及playbook的组成 1. Playbook 的功能 playbook 是由一个或多个 play 组成的列表 Playboot 文件使用 YAML 来写的 2. YAML 简介&#xff1a; 是一种表达资料序列的格式 &#xff0c; 类似 XML Yet Another Markup Language 3. 特点 可读性好 和脚本语言…