协程--面试资料收集

用户态线程

用户级线程由应用程序通过线程库实现,所有的线程管理工作都由应用程序负责 (包括进程切换)。在用户级线程中,线程的切换可以再用户态下完成,无需操作系统的干预。用户感受得到用户级线程,但是操作系统却意识不到他们的存在。

当操作系统不支持线程时,为了研究线程的可行性,研究人员编写了一个线程的函数库,用函数库来实现线程。这个线程库包含了创建线程、终止线程等,开发者可以通过调用这些函数来实现所需的功能。

这个线程库,是位于用户空间的,操作系统内核对这个库一无所知,所以从内核的角度看,它还是按正常的方式管理进程,即使用这个函数库创建出多个线程,这些线程一次也只能在一个CPU核上运行。当一个线程陷入了阻塞,从操作系统内核的角度来看就是进程阻塞了,那么整个进程就会进入阻塞态,在阻塞操作结束前,这个进程都无法得到 CPU 资源。那就相当于,该进程中所有的线程都被阻塞了。

事实上,这也是用户态线程的缺点。这些用户态线程只能占用一个核,无法做到并行加速,而且由于用户态线程对操作系统透明,操作系统无法主动切换线程。对此,开发者需要为用户态线程定制调度算法。

优点:

  • 管理开销小:创建、销毁不需要系统调用。
  • 切换成本低:用户空间程序可以自己维护,不需要操作系统自己调度。

缺点:

  • 与内核协作成本高:用户线程由用户空间进行管理,当它进行 I/O 的时候,需要频繁进行用户态到内核态的切换。
  • 线程间通信成本高:用户态线程的通信和同步机制是由内核提供的。当需要进行线程同步时,通信需要 IO,I/O需要系统调用,因此用户态线程需要支付额外的系统调用成本。
  • 无法利用多核优势:操作系统调度的仍然是这个线程所属的进程,所以无论每次一个进程有多少个用户态的线程,都只能并发执行一个线程,因此一个进程的多个线程无法利用多核的优势。
  • 当一个进程的一个用户态线程阻塞了,操作系统无法及时发现和处理阻塞问题,它不会更换执行其他线程,从而造成资源浪费。

内核态线程

内核级线程的管理工作(创建和撤销)由操作系统的内核程序完成,线程调度、切换等工作都由内核负责。因此,内核级线程的切换必然需要在核心态下才能完成。用户感受不到内核级线程,但是操作系统意识得到他们的存在。

操作系统只“看得见”内核级线程,因此只有内核级线程才是CPU分配的单位。

操作系统内核会提供一个应用程序设计接口API,供开发者使用内核线程。

为了实现线程,内核里有一个用来记录系统里所有线程的线程表。当需要创建一个新线程的时候,需要进行一个系统调用,然后由操作系统进行线程表的更新。

相比于用户态线程,操作系统知道内核态线程的存在,它可以自由调度各个线程,从而充分利用多核,实现真正的并行。

假如线程 A 阻塞了,与他同属一个进程的线程也不会被阻塞。这是内核级线程的优势。、

让操作系统进行线程调度,意味着每次切换线程,就需要「陷入」内核态,而操作系统从用户态到内核态的转变是有开销的,所以说内核级线程切换的代价要比用户级线程大。

还有很重要的一点——线程表是存放在操作系统固定的表格空间或者堆栈空间里,所以内核级线程的数量是有限的,扩展性比不上用户级线程。

创建一个新的线程时,就需要进行一次系统调用,然后由操作系统对线程表进行更新。

优点:

  • 可以利用多核 CPU 实现并行:操作系统知道内核态线程的存在,它可以自由调度各个线程,从而充分利用多核,实现真正的并行
  • 操作系统级优化:内核中的线程操作 I/O 不需要进行系统调用;进程中的一个线程被阻塞,内核能调度同一进程的其他线程(就绪态)占有CPU运行

缺点:

  • 创建成本高:创建的时候需要系统调用,也就是切换到内核态
  • 扩展性差:由一个内核程序管理,创建的数量不能太多
  • 切换成本较高:内核线程在用户态运行,线程调度和管理在内核实现。线程调度时,控制权从一个线程改变到另一线程,需要模式切换,系统开销较大。

协程

协程是用户级线程,是比线程更加轻量级的存在。它相当于一个特殊的函数,这个函数可以在某个地方挂起,并且可以重新在挂起处继续运行。它的调度完全由开发者进行调度,避免了内核态上下文切换造成的性能损失,从而突破了线程在IO上的性能瓶颈。

一个操作系统中可以有多个进程;一个进程可以有多个线程,一个线程可以有多个协程。

一个线程内的多个协程的运行是串行的,这点和多进程(多线程)在多核CPU上执行时是不同的。多进程在多核CPU上是可以并行的。当线程内的某一个协程运行时,其他协程必须挂起。

它是用于将异步代码同步化的编程机制,使得程序的执行流可以在多个并行事务之间切换但又不必承担切换带来的过高的性能损耗。因为协程切换是在线程内完成的,涉及到的资源比较少,不像线程(进程)切换那样,上下文的内容比较多,切换代价较大。协程本身是非常轻巧的,可以简单理解为只是切换了寄存器和协程栈的内容。这样代价就非常小。

线程安全

线程安全是指在多线程环境下,共享资源能够被多个线程同时访问而不会导致数据错误或程序异常。

线程是操作系统内核调度的,有CPU时间片的概念,进行抢占式调度。在所有线程相互独立且不会操作同一资源的模式下,抢占式的线程调度器是非常不错的选择,因为它可以保证所有的线程都可以被分到时间片不被垃圾代码所拖累。而如果操作同一资源,抢占式的线程为了保证线程安全,需要使用合适的同步机制,如互斥锁、信号量等,来控制对共享资源的访问和修改,从而避免出现竞争条件和数据冲突。

协程对内核来说是透明的,也就是系统并不知道有协程的存在,是完全由用户自己的程序进行调度的,因为是由用户程序自己控制的,那么就很难像抢占式调度那样做到强制CPU控制权切换到其他进程/线程,通常只能进行协作式调度,需要协程自己主动把控制权转让出去之后,其他协程才能执行。

与线程相比,协程这种主动让出型的调度方式更为高效。一方面,它让调用者自己来决定什么时候让出,比操作系统的抢占式调度所需要的时间代价要小很多。后者为了能恢复现场会在切换线程时保存相当多的状态,并且会非常频繁地进行切换。另一方面,协程本身可以做成用户态,每个协程的体积比线程要小得多,因此一个进程可以容纳数量相当可观的协程任务。

因为同一时间只能有一个协程任务运行,并且协程切换并不是系统态抢占式,那么协程一定是安全协程。

在操作共享变量的过程中,没有主动放弃执行权(await),也就是没有切换挂起状态,那就不需要加锁,执行过程本身就是安全的;可是如果在执行事务逻辑块中主动放弃执行权了,会分两种情况,如果在逻辑执行过程中我们需要判断变量状态,或者执行过程中要根据变量状态进行一些下游操作,则必须加锁,如果我们不关注执行过程中的状态,只关注最终结果一致性,则不需要加锁。

协程切换的问题

协程只有在等待I/O的过程中才能重复利用线程。协程本质是通过多路复用来完成的。

协程本身不是线程,只是一个特殊的函数,它不能被操作系统感知到(操作系统只能感知到进程和内核级线程),如果某个线程中的协程调用了阻塞IO,那么将会导致线程切换发生。因此只有协程是不够的,是无法解决问题的,还需要异步来配合协程。

因此,实际上我们可以把协程可以看做是一种用户级线程的实现,协程+异步才能发挥出协程的最大作用。

协程的使用

在一个线程多个协程的情况下,在内核看来只有一个线程在运行,这些协程事实上在串行执行,只能使用一个CPU核。如果想要高效利用CPU,还是得使用线程。协程最大的优势在于协程的切换比线程的切换快。

因此,计算型的操作,利用协程来回切换执行,没有任何意义,来回切换并保存状态反倒会降低性能。

协程适用于IO密集型任务。可以利用协程在IO等待时间就去切换执行其他任务,当IO操作结束后再自动回调,那么就会大大节省资源并提供性能,从而实现异步编程(不等待任务结束就可以去执行其他代码)。

协程栈

线程在切换时,它的中断状态会保存在线程栈中。而协程的特点是,对于某一个方法,可以执行到某个操作的时候 yield 出去,然后在某个时候再 resume。实现一个协程的关键点在于如何保存、恢复和切换上下文。

因此,按照是否开辟相应的调用栈来保存上下文,可以将协程分为两类:

有栈协程:每个协程都有自己的调用栈,类似与线程的调用栈

无栈协程:协程没有自己的调用栈,挂起点的状态通过状态机或闭包等语法实现。

微信的 libco、阿里的 cooobjc、Golang 中的 goroutine、Lua 中的协程都是有栈协程;类似 ES6、Dart 中的 await/async、Python 的 Generator、Kotlin 中的协程、C++20 中的 cooroutine 都是无栈协程。

有栈协程:

在内存中给每个协程开辟一个栈内存,当协程挂起时会将它的运行上下文从系统栈保存至其所分配的栈内存中,当协程恢复时会将其运行时上下文从栈内存中恢复至系统栈中。

优点:可以在任意函数调用层级的位置进行挂起。并转移调度权。

缺点:有栈协程会改变函数调用栈。由于有栈协程需要保存各个协程自己的运行时上下文,一般会通过堆来分类内存空间。如果内存分配过小,可能会产生栈溢出,如果内存分配过大,可能会产生内存浪费。当协程恢复时,需要将运行时上下文从堆中拷贝至栈中,存在一定的开销。

无栈协程:

无栈协程不会为各个协程开辟相应的调用栈。无栈协程通常是基于状态机或闭包来实现的。

基于状态机的解决方案一般是通过状态机,记录上次协程挂起时的位置,并基于此决定协程恢复时开始执行的位置。这个状态必须存储在栈以外的地方,从而避免状态与栈一同销毁。

相比于有栈协程,无栈协程不需要修改调用栈,也无需额外的内存来保存调用栈,因此它的开销会更小。但是,相比于保存运行时上下文这种实现方式,无栈协程的实现还是存在比较多的限制,最大缺点就是,它无法实现在任意函数调用层级的位置进行挂起。

协程调度器

1:1调度

1个协程绑定1个线程,这种最容易实现。协程的调度都由CPU完成了,但有一个缺点是协程的创建、删除和切换的代价都由CPU完成,上下文切换很慢,同等于线程切换。

N:1调度

N个协程绑定1个线程,优点就是协程在用户态线程即完成切换,不会陷入到内核态,这种切换非常的轻量快速。但也有很大的缺点,1个进程的所有协程都绑定在1个线程上,一是某个程序用不了硬件的多核加速能力,二是一旦某协程阻塞,造成线程阻塞,本进程的其他协程都无法执行了,根本就没有并发的能力了。

M:N调度

M个协程绑定N个线程,是N:1和1:1类型的结合,克服了以上2种模型的缺点,但实现起来最为复杂。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Hvv工具推荐——IWannaGetAll

OA基本上是每次hvv中都会被突破的,基本上也都会爆出各种各样的0day,如果真的0day防不住,那我们必须要把1day、nday做一遍检查。 IWannaGetAll 是一款专门针对主流OA(办公自动化)系统的漏洞检测和利用工具。 IWannaGe…

C++:组合和继承的区别

组合介绍以及与继承对比 什么是组合 (1)composition&#xff0c;组合&#xff0c;就是在一个class内使用其他多个class的对象作为成员 (2)用class tree做案例讲解 (3)组合也是一种代码复用方法&#xff0c;本质也是结构体包含 #include <iostream> #include <vector…

二四、3d人脸构建

一、下载github项目3dmm_cnn-master https://github.com/anhttran/3dmm_cnn.git 一个使用深度神经网络从单个图像进行 3D 人脸建模的项目,端到端代码,可直接根据图像强度进行 3D 形状和纹理估计;使用回归的 3D 面部模型,从检测到的面部特征点估计头部姿势和表情。…

大模型【Qwen2-7B本地部署(WEB版)】(windows)

大模型系列文章目录 Qwen2-7B本地部署&#xff08;WEB版&#xff09; 前言 大模型是截止2024年上半年最强的AI&#xff0c;Qwen2是刚出来的号称国内最强开源大模型。这是大模型系列的第一篇文章&#xff0c;旨在快速部署看看最近出来的大模型效果怎么样&#xff0c;效果ok的话…

【Pytorch】Conda环境pack打包迁移报错处理

文章目录 Anaconda虚拟环境打包一、源电脑的环境打包1.安装conda-pack工具2.确定环境3.打包环境4.将打包环境拷贝到U盘 二、环境迁移到目标电脑上三、异常处理pip install -e. 导致无法pack→忽略管理的文件已经被删除或者被覆盖→压缩成tar注意 重新激活环境 Anaconda虚拟环境…

PHP红包拓客微信小程序系统源码

&#x1f389;红包狂欢&#xff0c;客源滚滚来&#xff01;红包拓客微信小程序&#xff0c;营销新利器&#x1f680; &#x1f9e7;一、创意红包&#xff0c;吸引眼球 你还在为如何吸引顾客而烦恼吗&#xff1f;红包拓客微信小程序来帮你&#xff01;&#x1f381; 它以创意红…

系统服务综合作业01

题目&#xff1a; 现有主机 node01 和 node02&#xff0c;完成如下需求&#xff1a; 1、在 node01 主机上提供 DNS 和 WEB 服务 2、dns 服务提供本实验所有主机名解析 3、web服务提供 www.rhce.com 虚拟主机 4、该虚拟主机的documentroot目录在 /nfs/rhce 目录 5、该目录由 no…

妙笔生词与文心一言:歌词创作的优势争锋

在当今科技赋能创作的时代&#xff0c;妙笔生词智能写歌词软件和文心一言都在写歌词领域展现出各自独特的魅力。让我们深入探究它们的优势所在&#xff0c;看看谁能更胜一筹。 妙笔生词智能写歌词软件&#xff08;veve522&#xff09;以其专业性和针对性在歌词创作中崭露头角。…

Web3学习路线图,从入门到精通

前面我们聊了Web3的知识图谱&#xff0c;内容是相当的翔实&#xff0c;要从哪里入手可以快速的入门Web3&#xff0c;本篇就带你看看Web3的学习路线图&#xff0c;一步一步深入学习Web3。 这张图展示了Web3学习路线图&#xff0c;涵盖了区块链基础知识、开发方向、应用开发等内…

vue 数据类型

文章目录 ref 创建&#xff1a;基本类型的响应式数据reactive 创建&#xff1a;对象类型的响应式数据ref 创建&#xff1a;对象类型的响应式数据ref 对比 reactive将一个响应式对象中的每一个属性&#xff0c;转换为ref对象(toRefs 与 toRef)computed (根据计算进行修改) ref 创…

【两大3D转换SDK对比】HOOPS Exchange VS. CAD Exchanger

在现代工业和工程设计领域&#xff0c;CAD数据转换工具是确保不同软件系统间数据互通的关键环节。HOOPS Exchange和CAD Exchanger是两款备受关注的工具&#xff0c;它们在功能、支持格式、性能和应用场景等方面有着显著差异。 本文将从背景、支持格式、功能和性能、应用场景等…

程序员学长 | 快速学习一个算法,GAN

本文来源公众号“程序员学长”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;快速学习一个算法&#xff0c;GAN GAN 如何工作&#xff1f; GAN 由两个部分组成&#xff1a;生成器&#xff08;Generator&#xff09;和判别器&…

Windows电脑安装Python结合内网穿透轻松搭建可公网访问私有网盘

文章目录 前言1.本地文件服务器搭建1.1.Python的安装和设置1.2.cpolar的安装和注册 2.本地文件服务器的发布2.1.Cpolar云端设置2.2.Cpolar本地设置 3.公网访问测试4.结语 前言 本文主要介绍如何在Windows系统电脑上使用python这样的简单程序语言&#xff0c;在自己的电脑上搭建…

TF卡病毒是什么?如何防范和应对?

在存储芯片及存储卡领域&#xff0c;TF卡病毒是一个备受关注的话题。在本文中&#xff0c;拓优星辰将详细解释TF卡病毒的含义、来源以及如何防范和应对这一问题&#xff0c;帮助客户更好地了解和处理TF卡病毒的风险。 1. TF卡病毒的含义 TF卡病毒是指针对TF存储卡&#xff08;T…

【案例】python集成OCR识别工具调研

目录 一、前言二、Tesseract_OCR2.1、安装过程2.2、python代码使用三、PaddleOCR3.1、安装过程3.2、python代码使用四、EasyOCR五、ddddOCR六、CnOCR七、总结一、前言 因项目需要OCR识别能力,且要支持私有化部署。本文将对比市场一些开源的OCR识别工具,从中选择适合项目需要…

逻辑回归(纯理论)

1.什么是逻辑回归&#xff1f; 逻辑回归是一种常用的统计学习方法&#xff0c;主要用于解决分类问题。尽管名字中包含"回归"&#xff0c;但它实际上是一种分类算法 2.为什么机器学习需要使用逻辑回归 1.二元分类 这是逻辑回归最基本和常见的用途。它可以预测某个事…

【备战秋招】——算法题目训练和总结day3

【备战秋招】——算法题目训练和总结day3&#x1f60e; 前言&#x1f64c;BC149简写单词题解思路分析代码分享&#xff1a; dd爱框框题解思路分析代码分享&#xff1a; 除2&#xff01;题解思路分析代码分享&#xff1a; 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff…

多周期路径的约束与设置原则

本节将回顾工具检查建立保持时间的原则&#xff0c;接下来介绍设置多周期后的检查原则。多周期命令是设计约束中常用的一个命令&#xff0c;用来修改默认的建立or保持时间的关系。基本语法如下 默认的建立时间与保持时间的检查方式 DC工具计算默认的建立保持时间关系是基于时钟…

EXSI 实用指南 2024 -编译环境 Mac OS 安装篇(一)

1. 引言 在现代虚拟化技术的快速发展中&#xff0c;VMware ESXi 作为领先的虚拟化平台&#xff0c;凭借其高性能、稳定性和丰富的功能&#xff0c;广泛应用于企业和个人用户。ESXi 能有效地提高硬件资源利用率&#xff0c;并简化 IT 基础设施的管理。然而&#xff0c;如何在 V…

RK3568平台(显示篇)主屏副屏配置

一.主屏副屏配置 目前在RK3568平台上有两路HDMIOUT输出&#xff0c;分别输出到两个屏幕上&#xff0c;一路配置为主屏&#xff0c;一路配置为副屏。 硬件原理图&#xff1a; &hdmi0_in_vp2 {status "okay"; };&hdmi1_in_vp0 {status "okay"; }…