golang学习笔记(协程的基础知识)

news2024/11/25 16:43:57

golang的协程

协程是一种轻量级的线程,它可以实现并发执行的并行操作。协程是Go语言中的一个核心特性,它使得程序能够以并发的方式运行,并且非常高效。与传统的线程相比,协程的创建和销毁成本非常低,可以方便地启动大量的协程来执行并行操作。

Golang的协程不同于其他语言中的线程或进程,它们是由Go语言的运行时系统调度的。协程的调度是基于协作式的,即协程自己主动让出CPU的控制权,而不是依赖于操作系统的调度器。

线程池的缺陷

在高并发应用中频繁创建线程会造成不必要的开销, 所以有了线程池。线程池中预先保存一定数量的线程, 而新任务将不再以创建线程的方式去执行, 而是将任务发布到任务队列, 线程池中的线程不断的从任务队列中取出任务并执行, 可以有效的减少线程创建和销毁所带来的开销。下图是一个简单的线程池的案例:
在这里插入图片描述
我们把任务队列中的每一个任务称作G, 而G往往代表一个函数。 线程池中的线程worker线程不断的从任务队列中取出任务并执行。 而worker线程的调度则交给操作系统进行调度。

如果worker线程执行的G任务中发生系统调用, 则操作系统会将该线程置为阻塞状态, 也意味着该线程在怠工, 也意味着消费任务队列的worker线程变少了, 也就是说线程池消费任务队列的能力变弱了。如果任务队列中的大部分任务都会进行系统调用, 则会让这种状态恶化, 大部分worker线程进入阻塞状态, 从而任务队列中的任务产生堆积。

解决这个问题的一个思路就是重新审视线程池中线程的数量, 增加线程池中线程数量可以一定程度上提高消费能力,但随着线程数量增多, 由于过多线程争抢CPU, 消费能力会有上限, 甚至出现消费能力下降。 如下图所示:
在这里插入图片描述

Goroutine调度器

线程数过多, 意味着操作系统会不断的切换线程, 频繁的上下文切换就成了性能瓶颈。 Go提供一种机制, 可以在线程中自己实现调度, 上下文切换更轻量, 从而达到了线程数少, 而并发数并不少的效果。 而线程中调度的就是Goroutine。
Goroutine主要概念

  • G( Goroutine) : 即Go协程, 每个go关键字都会创建一个协程。
  • M( Machine) : 工作线程,在Go中称为Machine。
  • P(Processor): 处理器( Go中定义的一个摡念, 不是指CPU) ,包含运行Go代码的必要资源, 也有调度goroutine的能力
    M必须拥有P才可以执行G中的代码, P含有一个包含多个G的队列, P可以调度G交由M执行。 其关系如下图所示:
    在这里插入图片描述

图中M是交给操作系统调度的线程, M持有一个P, P将G调度进M中执行。 P同时还维护着一个包含G的队列( 图中灰色部分) , 可以按照一定的策略将不能的G调度进M中执行。

P的个数在程序启动时决定, 默认情况下等同于CPU的核数, 由于M必须持有一个P才可以运行Go代码, 所以同时运行的M个数, 也即线程数一般等同于CPU的个数, 以达到尽可能的使用CPU而又不至于产生过多的线程切换开销。

Goroutine调度策略

队列轮转

上图中可见每个P维护着一个包含G的队列, 不考虑G进入系统调用或IO操作的情况下, P周期性的将G调度到M中执行,执行一小段时间, 将上下文保存下来, 然后将G放到队列尾部, 然后从队列中重新取出一个G进行调度。

除了每个P维护的G队列以外, 还有一个全局的队列, 每个P会周期性的查看全局队列中是否有G待运行并将其调度到M中执行, 全局队列中G的来源, 主要有从系统调用中恢复的G。 之所以P会周期性的查看全局队列, 也是为了防止全局队列中的G被饿死。

系统调用

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

当M运行的某个G产生系统调用时, 如下图所示:
在这里插入图片描述
如图所示, 当G0即将进入系统调用时, M0将释放P, 进而某个空闲的M1获取P, 继续执行P队列中剩下的G。 而M0由于陷入系统调用而进被阻塞, M1接替M0的工作, 只要P不空闲, 就可以保证充分利用CPU。

M1的来源有可能是M的缓存池, 也可能是新建的。 当G0系统调用结束后, 跟据M0是否能获取到P, 将会将G0做不同的处理:

  1. 如果有空闲的P, 则获取一个P, 继续执行G0。
  2. 如果没有空闲的P, 则将G0放入全局队列, 等待被其他的P调度。 然后M0将进入缓存池睡眠

工作量窃取

多个P中维护的G队列有可能是不均衡的, 比如下图:
在这里插入图片描述
竖线左侧中右边的P已经将G全部执行完, 然后去查询全局队列, 全局队列中也没有G, 而另一个M中除了正在运行的G外, 队列中还有3个G待运行。 此时, 空闲的P会将其他P中的G偷取一部分过来, 一般每次偷取一半。 偷取完如右图所示。

抢占式调度

goroutine设计之初为协作式调度,用户负责在各个goroutine之间协作式执行任务。协作式调度意味着希望协程自己会主动让出执行权,用户在加锁,读写通道时会主动让出执行权。

垃圾回收器是需要stop the world的。如果垃圾回收器想要运行了,那么它必须先通知其它的goroutine合作停下来,这会造成较长时间的等待时间。考虑一种很极端的情况,所有的goroutine都停下来了,只有其中一个没有停,那么垃圾回收就会一直等待着没有停的那一个。

抢占式调度可以解决这种问题,在抢占式情况下,如果一个goroutine运行时间过长,它就会被剥夺运行权。

Golang协程的用法

在Go语言中,要创建一个协程,只需在函数调用前加上关键字"go"。下面是一个简单的示例:

go 函数名()

这样就创建了一个新的协程,并在该协程中执行相应的函数。协程会与主线程并发执行,不会阻塞主线程的执行。

协程之间可以通过通道(Channel)进行通信。通道是一种在多个协程之间同步和传递数据的机制,它能够保证并发安全。通过通道,协程可以发送和接收数据,实现协程之间的协作。

package main

import (
	"fmt"
	"time"
)

func longRunningTask() (res int) {
	time.Sleep(time.Second)
	for i := 0; i < 10; i++ {
		res += i
	}
	return res
}

func main() {
	result := make(chan int)

	go func() {
		result <- longRunningTask()
	}()

	fmt.Println("Waiting for result...")
	fmt.Println("Result:", <-result)
}

在这里插入图片描述

参考文档

参考文档一

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

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

相关文章

三维坐标点按剖面分类

一、写在前面 ①配套文件&#xff1a;根据剖面对三维坐标点&#xff08;X,Y,Z&#xff09;分类资源-CSDN文库 ②脱敏处理&#xff1a;蚀变数据已采用随机数生成覆盖 ③剖面坐标按顺序排列在“剖面坐标点.xlsx”文件中 二、3点确定空间中平面方程 原理&#xff1a; 设3点A&…

C++深度解析教程笔记2

C深度解析教程笔记2 第3课 - 进化后的 const 分析实验-C与C的const区别实验-C与C的const区别&const作用域 第4课 - 布尔类型和引用小结 本文学习自狄泰软件学院 唐佐林老师的 C深度解析教程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 第3课 - 进化后…

列转行(spark 与presto语法)

一、Presto 语法 原始数据&#xff1a; 期望数据&#xff1a; 代码&#xff1a; SELECT info, value FROM ( select 张三 as name,18 as age,男 as gender,清华 as schoolunion allselect 李四 as name,18 as age,男 as gender,清华 as school ) as a CROSS JOIN UNNEST(…

Unreal 编辑器工具 批量重命名资源

右键 - Editor Utilities - Editor Utility Blueprint&#xff0c;基类选择 Asset Action Utility 在类默认值内&#xff0c;可以添加筛选器&#xff0c;筛选指定的类型 然后新建一个函数&#xff0c;加上4个输入&#xff1a;ReplaceFrom&#xff0c;ReplaceTo&#xff0c;Add…

使用Android Studio 搭建AOSP FrameWork 源码阅读开发环境

文章目录 概述安装Android Studio编译源码使用Android Studio打开源码制作ipr文件直接编译成功后自动打开Android Studio 修改SystemUI验证开发环境 概述 我们都知道Android的系统源码量非常之大&#xff0c;大致有frameworka层源码&#xff0c;硬件层(HAL)源码&#xff0c;内…

机器学习笔记-18

异常检测问题 异常检测虽然主要用于无监督学习问题上&#xff0c;但是和监督学习问题很相似。 异常检测(Anomaly Detection)&#xff1a;给定正确样本集{ x ( 1 ) , x ( 2 ) . . . x ( n ) x^{(1)},x^{(2)}...x^{(n)} x(1),x(2)...x(n)}&#xff0c;记新样本即要检测的样本为…

堆排序以及TOP-K问题

片头 嗨&#xff01;小伙伴们&#xff0c;大家好&#xff01;今天我们来深入理解堆这种数据结构&#xff0c;分析一下堆排序以及TOP-K问题&#xff0c;准备好了吗&#xff1f;我要开始咯&#xff01; 一、堆排序 这里我们先假设要排成升序&#xff0c;也就是从左到右&#xf…

JSP简介——[JSP]1

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;大大会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

基于php+mysql+html图书管理系统(含实训报告)

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

【C++】命名冲突了怎么办?命名空间来解决你的烦恼!!!C++不同于C的命名方式——带你认识C++的命名空间

命名空间 导读一、什么是C?二、C的发展三、命名空间3.1 C语言中的重名冲突3.2 什么是命名空间&#xff1f;3.3 命名空间的定义3.4 命名空间的使用环境3.5 ::——作用域限定符3.6 命名空间的使用方法3.6.1 通过作用域限定符来指定作用域3.6.2 通过关键字using和关键字namespace…

如何用 Redis 实现延迟队列?

延迟队列是一种常见的消息队列模式&#xff0c;用于处理需要延迟执行的任务或消息。Redis 是一种快速、开源的键值对存储数据库&#xff0c;具有高性能、持久性和丰富的数据结构&#xff0c;因此很适合用于实现延迟队列。在这篇文章中&#xff0c;我们将详细讨论如何使用 Redis…

51单片机两个中断及中断嵌套

文章目录 前言一、中断嵌套是什么&#xff1f;二、两个同级别中断2.1 中断运行关系2.2 测试程序 三、两个不同级别中断实现中断嵌套3.1 中断运行关系3.2 测试程序 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 课程需要&#xff1a; 提示&#x…

Mysql基础(四)DML之insert语句

一 insert 语句 强调&#xff1a; 本文介绍的内容很基础,仅做记录用,参考价值较少 ① 总述 目的&#xff1a; 增加rows记录1、完整格式insert [into] 表名[字段名1[, 字段名2]] value[s](值1, 值2);备注&#xff1a;指定部分字段添加,没有被指定的字段要么会自动增长,要…

微信小程序demo-----制作文章专栏

前言&#xff1a;不管我们要做什么种类的小程序都涉及到宣传或者扩展其他业务&#xff0c;我们就可以制作一个文章专栏的页面&#xff0c;实现点击一个专栏跳转到相应的页面&#xff0c;页面可以有科普类的知识或者其他&#xff0c;然后页面下方可以自由发挥&#xff0c;添加联…

ensp 配置s5700 ssh登陆

#核心配置 sys undo info-center enable sysname sw1 vlan 99 stelnet server enable telnet server enable int g 0/0/1 port lin acc port de vlan 99 q user-interface vty 0 4 protocol inbound ssh authentication-mode aaa q aaa local-user admin0 password cipher adm…

结构分析的有限元法及matlab实现(徐荣桥)|【PDF教材+配套案例Matlab源码】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

为何数据库推荐将IPv4地址存储为32位整数而非字符串?

目录 一、IPv4地址在数据库中的存储方式&#xff1f; 二、IPv4地址的存储方式比较 &#xff08;一&#xff09;字符串存储 vs 整数存储 &#xff08;二&#xff09;IPv4地址"192.168.1.8"说明 三、数据库推荐32位整数存储方式原理 四、存储方式对系统性能的影响…

服务器IP选择

可以去https://ip.ping0.cc/查看IP的具体情况 1.IP位置--如果是国内用&#xff0c;国外服务器的话建议选择日本&#xff0c;香港这些比较好&#xff0c;因为它们离这里近&#xff0c;一般延时低&#xff08;在没有绕一圈的情况下&#xff09;。 不过GPT的话屏蔽了香港IP 2. 企…

C++ | Leetcode C++题解之第64题最小路径和

题目&#xff1a; 题解&#xff1a; class Solution { public:int minPathSum(vector<vector<int>>& grid) {if (grid.size() 0 || grid[0].size() 0) {return 0;}int rows grid.size(), columns grid[0].size();auto dp vector < vector <int>…

WebAuthn 无密码身份认证

文章目录 WebAuthn简介工作原理组成部分架构实现注册认证应用场景案例演示 WebAuthn简介 WebAuthn&#xff0c;全称 Web Authentication&#xff0c;是由 FIDO 联盟&#xff08;Fast IDentity Online Alliance&#xff09;和 W3C&#xff08;World Wide Web Consortium&#x…