【Go专家编程——协程】

1 协程的概念

1.1 基本概念

  • 进程是应用程序的启动实例,每个进程都有独立的内存空间,不同进程通过进程间的通信方式来通信
  • 线程从属于进程,每个进程至少包含一个线程,线程是CPU调度的基本单元,多个线程之间可以共享进程的资源并通过共享内存等线程间的通信方式来通信。
  • 协程可以理解为一种轻量级的线程,协程不受操作系统调度,协程调度器由用户应用程序提供,协程调度器按照调度策略把协程调度到线程中运行。

1.2 协程优势

在高并发应用中频繁创建线程会造成不必要的开销,所以由了线程池技术。使用的时候从中取出,使用完放回即可。
当线程在任务重发生系统调用时,会发生阻塞,则该线程会暂停执行任务。如果大量的线程都发生了系统调用,则会对系统发生阻塞,使任务得不到即使的处理。

  • 增加线程池中线程的数量在一定程度上可以提高处理能力
  • 但线程的增多,也会导致上下文切换的开销变大

那么当发生阻塞时,是否可以将当前任务放在一边,先执行其他任务呢?

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

2 调度模型

2.1 线程模型

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

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

2.2 Go调度器模型

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

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

相关信息:

  • M必须持有P才可以执行代码
  • M也会被系统调用阻塞
  • P的个数在程序启动时决定,默认情况下等同于CPU的核数。但可以通过GOMAXPROCS这个环境变量指定

一个简单的调度器模型如下图所示:
在这里插入图片描述

  • 上图中包含2个工作线程M
  • 每个M持有一个P
  • 每个M中有一个协程在运行(已标记)
  • 其他背景的协程正在等待被调度,每个处理器P拥有宇哥runqueues队列
  • 此外还有一个全局的runqueues队列,由多个处理器共享

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

3 调度策略

3.1 队列轮转

  • 每个处理器P维护者一个协程G的队列,处理器P依次将协程G调度到M中执行
  • 协程G执行结束后,处理器P会再次调度一个协程G到M中执行
  • 同时P会周期性查看全局变量中是否有待运行的G,并将其调度到M中运行
  • 全局变量中的G主要来自于系统调用中恢复的G
  • 周期性查看全局队列的目的是为了防止全局队列中的G长时间得不到调度机会而被“饿死”

3.2 系统调用

  • 协程发生系统调度时,对应的工作线程会被阻塞
  • 前面提到P的个数默认等于CPU的个数,每个M必须持有一个P才可以执行G
  • 一般情况下M个的个数会略大于P的个数。
  • 多出来的M将会在G发生系统调用时发生作用。
  • Go也提供了一个M的的池子,需要时从池子中获取,用完放回。不够时再创建。
    在这里插入图片描述
  • 当G0即将进入系统调用时
  • M0释放P
  • 冗余的M1获得P,继续执行P队列中剩下的G(冗余的M的来源可能是缓存池,也可能是新建的)
  • M0由于陷入系统调用而被阻塞,M1接替了M0的工作
  • 只要P不空闲,就可以充分利用CPU
  • 当G0结束系统调用后,根据能否获得P,对G0进行不同的处理
    • 如果有空闲的P,则获取一个P,继续执行G0
    • 如果没有空闲的P,则将G0放入全局队列,等待被其他P调度,然后M0将进入缓冲休眠

3.3 工作量窃取

说白了就是当前P已经将自己队列中的任务全部干完了,而全局队列中又没有新的G。于是从别人的队列中获取一半的工作量。

3.4 抢占式调度

所谓抢占式调度,是指避免某个协程长时间执行,而阻碍其他协程被调用的机制。

  • 调度器会监控每个协程执行的时间
  • 时间过长且有其他协程子在等待时
  • 会把协程暂停,转而调度等待的协程

3.5 GOMAXPROCS对性能的影响

一般来讲,程序运行时就将GOMAXPROCS的大小设置为CPU的核数,可让Go程序充分利用CPU。在某些I/O密集型的应用中,不妨把GOMAXPROCS的值设置得大一些,或许会有更好的效果。

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

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

相关文章

PCIe总线-事物层之TLP请求和完成报文格式介绍(六)

1.概述 TLP报文按照类型,可以大致分为4中类型,分别是IO请求报文、存储器请求报文、配置请求报文、完成报文和消息请求报文。IO请求报文可分为IO读请求(不携带数据)和IO写请求(携带数据)。存储器请求报文可…

架构师系列-定时任务解决方案

定时任务概述 在很多应用中我们都是需要执行一些定时任务的,比如定时发送短信,定时统计数据,在实际使用中我们使用什么定时任务框架来实现我们的业务,定时任务使用中会遇到哪些坑,如何最大化的提高定时任务的性能。 我…

【文末附gpt升级方案】前沿人工智能安全承诺:OpenAI、微软、智谱AI等全球16家公司的共同行动

前沿人工智能安全承诺:OpenAI、微软、智谱AI等全球16家公司的共同行动 一、引言 随着人工智能(AI)技术的飞速发展,其在全球范围内的应用日益广泛,从智能家居到自动驾驶,从医疗诊断到金融分析,…

C语言——函数指针与指针函数

一、函数指针 1、定义 顾名思义,函数指针就是函数的指针。它是一个指针,属于一个数据类型,其指向一个函数。如定义一个函数,其入口地址就是这个函数的指针,是个常量,可以用该常量给函数指针类型的变量赋值&…

Spark-RDD-依赖关系详解

Spark概述 Spark-RDD概述 Spark-RDD-依赖关系 在Apache Spark中,RDD(Resilient Distributed Dataset)是一种基本的抽象数据结构,代表了分布式的、不可变的数据集。 RDD之间的依赖关系在Spark中非常重要,因为它们决定了…

汇编语言(一)

寄存器:cpu中可以储存数据的器件(AX,BX) 汇编语言的组成:1.汇编指令 2.伪指令 3.其他符号 存储器:cpu,传入指令和数据,加以运算。(内存) 指令和数据&#…

DBAPI怎么进行数据格式转换

DBAPI如何进行数据格式的转换 假设现在有个API,根据学生id查询学生信息,访问API查看数据格式如下 {"data":[{"name":"Michale","phone_number":null,"id":77,"age":55}],"msg"…

【java程序设计期末复习】chapter1 java入门

java入门 java的特点 (1)简单 Java要比C简单,C中许多容易混淆的概念,或者被Java弃之不用了,或者以一种更清楚更容易理解的方式实现 (2)面向对象 Java是面向对象的编程语言 (3&…

【一站式学会Kotlin】第九节:inline 内联函数

作者介绍: 百度资深Android工程师T6,在百度任职7年半。 目前:成立赵小灰代码工作室,欢迎大家找我交流Android、微信小程序、鸿蒙项目。= 一:通俗易懂的人工智能教程:https://www.captainbed.cn/nefu/ 点一下,打开新世界的大门。 二:【一站式学会Kotlin】免费领取:作者…

如何关闭或者减少屏蔽 CloudFlare 的真人检测

经常浏览境外网站的应该常碰到一个真人检测的提示(如下图所示)。最近,明月就收到了一个知乎上的付费咨询:问我如何去掉这个提示,由此明月也特别的研究了一下这个“真人检测”,这算是 CloudFlare 的一个特色了,基本上大家看到站点访问有这个提示的几乎都是用了 CloudFlar…

xjoi题库一级1-10段题解(c语言版)

xjoi题库一级一段 xjoi题库一级二段 xjoi题库一级三段 xjoi题库一级四段 xjoi题库一级五段

比特币的理论上限是多少个?

标签: 比特币的理论上限; 已经挖出多少个比特币; 问题:比特币的理论上限是多少个?截至2023年10月,已经挖出多少个比特币出来了? 比特币的理论上限 比特币的设计者中本聪在比特币协议中设定了比特币的最大供应量为 21,000,000(2100万)个。这个上限是通过一种称为“减…

CSS3优秀动画代码示例

目录 旋转立方体悬停效果动画路径动画纯CSS进度条文字打字机效果3D翻转卡片SVG路径跟随动画SVG心跳动画旋转文字手风琴效果

【同构字符串】python

思路: 先记录同一个值出现的次数,再将字典中的值取出,比较2个列表即可 代码: class Solution:def isIsomorphic(self, s: str, t: str) -> bool:dit1dict()dit2dict()for i in range(len(s)):if s[i] not in dit1:dit1[s[i…

01.并发编程简介

1 什么是并发编程 所谓并发编程是指在一台处理器上“同时”处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生。 2 为什么我们要学习并发编程? 最直白的原因就是因为面试需要,大厂的 Java 岗的并发编程能力属于标配。 而在非大厂…

Stanford斯坦福 CS 224R: 深度强化学习 (6)

CS 224R 离线强化学习:第二部分 课程介绍请看第一节内容 课程回顾 离线强化学习、数据约束和保守性 离线强化学习旨在利用离线数据,重复使用离线数据是有益的。其关键挑战是由于 π β \pi_\beta πβ​ 和 π θ \pi_\theta πθ​ 之间的偏移导致…

CentOS 7.9部署宝塔面板超详细

CentOS7 部署宝塔面板 Linux的宝塔面板搭建起来非常轻松,也可以用一句话来形容,如果喝水一样简单,只需一条命令剩下的交给时间,几分钟就能部署好,然后就可以直接进行登录,直接可以安装LNMP、LAMP平台&…

【2024】LeetCode HOT 100——动态规划

目录 1. 爬楼梯1.1 C++实现1.2 Python实现1.3 时空分析2. 杨辉三角2.1 C++实现2.2 Python实现2.3 时空分析3. 打家劫舍3.1 C++实现3.2 Python实现3.3 时空分析4. 完全平方数4.1 C++实现4.2 Python实现<

海外仓储管理系统:提升效率,标准化海外仓管理,科技赋能业务

海外仓作为跨境物流的关键一环&#xff0c;完全可以说海外仓的效率直接决定了后续物流的整体运作效率。 对于海外仓而言&#xff0c;一套高效&#xff0c;易用的海外仓储系统&#xff0c;无疑将成为提升企业竞争力的重要工具&#xff0c;帮助海外仓实现从野蛮生长到标准化管理…

2024.05.26 第 399 场周赛

Leetcode 第 399 场周赛 优质数对的总数 I Leetcode 优质数对的总数 I 给你两个整数数组 nums1 和 nums2&#xff0c;长度分别为 n 和 m。同时给你一个正整数 k。 如果 nums1[i] 可以被 nums2[j] * k 整除&#xff0c;则称数对 (i, j) 为 优质数对&#xff08;0 < i < n…