Go——协程

协程

协程是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.mzph.cn/news/220529.shtml

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

相关文章

记录 | vscode禁止插件自动更新的方法

shift command p 打开然后输入 > setting.json,选择用户设置 在 settings.json 配置文件中增加一项: "extensions.autoUpdate": false,

ohpm : 无法将“ohpm”项识别为 cmdlet、函数...

这是因为没有在环境变量里配置 Ohpm. 左上角File->Settings,找到Ohpm放的路径 bin目录下,然后复制 此电脑->右键属性->高级系统设置->环境变量->系统变量找到Path,添加刚才复制的那一行 重启 DevEco ,在Terminal输入 ohpm -v ,出现版本号就欧了 如果…

Python中容易被忽视的核心功能

Python是一门富有魅力的编程语言,拥有丰富的功能和库,以及强大的社区支持。然而,有一些核心功能经常被忽视,而它们实际上可以极大地提高代码的质量、可读性和性能。 1. 解析命令行参数的argparse库 很多Python开发者在编写命令行…

开关电源测试之电源漏电流测试方法分享

一、外观检测 检查开关电源外观是否完好,是否有破损、变形、漏油等情况。 二、检测火线和零线的电流 实时测量火线和零线的电流,当两个电流值不相等且都不为零时断开零线,然后测火线的电流。当火线电流不为0时,判断电流为漏电流状…

02.尚医通 Mybatis-Plus

1、前期准备 a. 创建数据库 CREATE TABLE USER (id BIGINT(20)NOT NULL COMMENT 主键ID,NAME VARCHAR(30)NULL DEFAULT NULL COMMENT 姓名,age INT(11)NULL DEFAULT NULL COMMENT 年龄,email VARCHAR(50)NULL DEFAULT NULL COMMENT 邮箱,PRIMARY KEY (id) );INSERT INTO user…

振弦采集仪:工程安全监测的“智能助手”

振弦采集仪:工程安全监测的“智能助手” 振弦采集仪是一种用于工程安全监测的设备,它可以被视为工程安全监测的“智能助手”。振弦采集仪通过测量结构物振动的频率和振幅来判断结构物的安全性,并实时监测结构物的变化。 振弦采集仪可以广泛…

番茄病虫害检测系统:融合感受野注意力卷积(RFAConv)改进YOLOv8

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 番茄是全球重要的蔬菜作物之一,具有广泛的经济和营养价值。然而,番茄病虫害的严重威胁导致了产量和质量的损失。因此,开发一种…

@RequestParam的使用

RequestParam使用 (1)不加RequestParam前端的参数名需要和后端控制器的变量名保持一致才能生效 (2)不加RequestParam参数为非必传,加RequestParam写法参数为必传。但RequestParam可以通过RequestParam(required fals…

Hadoop3.x完全分布式环境搭建Zookeeper和Hbase

集群规划 IP地址主机名集群身份192.168.138.100hadoop00主节点192.168.138.101hadoop01从节点192.168.138.102hadoop02从节点 Hadoop完全分布式环境搭建请移步传送门 先在主节点上进行安装和配置,随后分发到各个从节点上。 1. 安装zookeeper 1.1 解压zookeeper并…

spring 笔记三 Spring与Web环境集成

文章目录 Spring与Web环境集成ApplicationContext应用上下文获取方式导入Spring集成web的坐标置ContextLoaderListener监听器通过工具获得应用上下文对象SpringMVC概述SpringMVC快速入门 Spring与Web环境集成 ApplicationContext应用上下文获取方式 应用上下文对象是通过new …

RFID射频识别技术在鞋业中的应用

RFID射频识别技术在鞋业中的应用 在鞋业制造、入库、出库、货物运输的时候都会遇到一个大问题,货物的管理和盘点,传统的人工盘点不但费时费力,还会有人为统计出错的情况出现。十分不方便货物的管理,对货物的出入库和运输造成不少…

2021-2023年历年地震数据,shp矢量数据,含时间、位置、类型、震级等信息

基本信息. 数据名称: 历年地震数据 数据格式: Shp 数据时间: 2021-2023年 数据几何类型: 点 数据坐标系: WGS84坐标系 数据来源:网络公开数据 数据字段: 序号字段名称字段说明1dzlx地震类型2zj震级3zysd震源深度(米)…

MidJourney笔记(7)-Seeds

我相信很多人在使用MidJourney的时候,都会遇到一个问题,就是如何保持生成图像的一致性,或者相对一致性,差异性不是很大。此时,我们就需要引入一个seed值,类似给这个提示词生成的图片做一个id标识。 那这个seed值怎么使用? 其实,在我们每次生成的图片,都有有一个seed值…

2006年全国水土流失防治区数据,shp/excel格式,多字段,包含防治区名称、类型、编码、二级编码等

基本信息. 数据名称: 全国水土流失防治区数据 数据格式: Shp、Excel 数据时间: 2006年 数据几何类型: 面 数据坐标系: WGS84坐标系 数据来源:网络公开数据 数据字段: 序号字段名称字段说明1city_dm城市代码2city城市名称3mc防治区名称4bhlx…

保姆级 Keras 实现 YOLO v3 三

保姆级 Keras 实现 YOLO v3 三 一. 分配 anchor box二. 正负样本匹配规则三. 为每一个 anchor box 打标签3.1 anchor box 长什么样?3.2 每一个 anchor box 标签需要填充的信息有哪些?3.3 ( Δ x , Δ y , Δ w , Δ h ) (\Delta x, \Delta y, \Delta w, \Delta h) (Δx,Δy,…

DC-DC变换集成电路B34063——工作电压范围宽,静态电流小

B34063为一单片DC-DC变换集成电路,内含温度补偿的参考电压源(1.25V)、比较器、能有效限制电流及控制工作周期的振荡器,驱动器及大电流输出开关管等,外配少量元件,就能组成升压、降压及电压反转型DC-DC变换器。 主要特点: ● 工作…

【wimdows电脑上管理员账户与管理员身份的区别】

管理员账户 在控制面板的用户账户中,点击更改账户类型,可以看到目前的账户是“管理员账户”还是“标准账户”。 管理员身份 在快捷方式上右击,可以看到,可以选择以管理员身份运行该软件。 如何查看某个应用是否以管理员身份…

OpenHarmony应用开发——更改应用名称和图标

一、前言 相比其他,可能学者更希望学到的就是更改应用名称和图标,当一个自己的程序运行在手机上的时候,或许更有成就感...... 二、详细步骤 首先,我们要先找到声明应用图标和应用名称的地方。如下图所示,在entry ->…

RocketMQ容器化最佳实践

前言 在上一篇文章基于RocketMQ实现分布式事务我们完成基于消息队列实现分布式事务,为了方便后续的开发和环境统一,我们决定将RocketMQ容器化部署到服务器上。所以这篇文章就来演示一下笔者基于docker-compose完成RocketMQ容器化的过程。 本篇文章为了…

【笔试强化】Day 1

文章目录 一、单选1.2.3.4.5.6. (写错)7. (不会)8. (常错题)9.10. (写错) 二、编程1. 组队竞赛题目:题解:代码: 2. 删除公共字符题目:…