总说上下文切换耗性能,那他到底耗了多少性能?

大家好,我是「云舒编程」,今天我们来聊聊上下文切换性能消耗。

文章首发于微信公众号:云舒编程

关注公众号获取:
1、大厂项目分享
2、各种技术原理分享
3、部门内推

一、前言

   众所周知,操作系统是一个分时复用系统,通过将CPU时间分为好几份。系统在很短的时间内,将 CPU 轮流分配给它们,从而实现多任务同时运行的错觉。

   伴随着的还有一个词是上下文切换,无论在工作中还是面试中,我们总会听到要减少线程、进程的上下文切换,因为上下文切换的代价比较高,会影响性能。

    今天我们就来详细说说上下文切换到底在切换什么,以及如何可视化的观察上下文切换的代价,它是怎么影响程序性能的。

二、进程是什么

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。from:百科

直白的说就是假设你去组织一场活动,那么你肯定会需要记录活动需要的物质、人员、时间安排,在什么时间点应该做哪些事情。这些事情你肯定不会单纯记录在脑子里,会找一个文档记录下来。
同理,当一个程序需要运行时,操作系统也需要记录该程序使用了多少内存,打开了什么文件,程序运行到哪里了,这些信息都需要记录下来,而进程就充当了这个角色,也就是百科中说的:“是系统进行资源分配的基本单位”。

2.1、进程资源

更详细些,一个进程会拥有如下资源,其中带*号是每个进程都有独立一份,有了这样的设计结构,多个进程就能并发运行了。
图片

三、上下文切换到底在切换什么?

    有了CPU的时间片和进程后,操作系统就可以将程序执行起来了。假设有三个进程A,B,C。首先是A获得了CPU时间片,待A的时间片结束后,操作系统会挑选B或者C进行执行。  
    那么这里就存在一个问题,A程序可能并没有执行完,这个时候被临时中断了,下一次该怎么执行呢?为了解决这个问题,于是提出了上下文的概念:“进程运行过程中用到的资源,进程的状态,执行到了哪里”。

    在把A切换出去之前,首先把上下文保存下来,这样等到再次执行A的时候就可以从上次执行的状态继续执行,从而达成没有中断过的假象。  

图片
更加详细的解释是:
每个程序运行前,CPU需要知道从哪里加载任务,从哪里开始运行,有哪些指令。而这些都需要CPU寄存器、程序计数器、内存管理单元(MMU)配合完成。

一、寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。寄存器拥有非常高的读写速度,所以在寄存器之间的数据传送非常快。

二、程序计数器:程序计数器是用于存放下一条指令所在单元的地址的地方。当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。

三、内存管理单元(MMU):通过虚拟内存和物理内存的映射,使的每个程序都认为自己可以使用完整的内存。详细解释:https://baike.baidu.com/item/MMU/4542218

上下文切换就是将A进程存储在CPU寄存器,程序计数器,MMU中的数据取出来,然后将B进程的数据放进去。而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

四、有哪些类型的上下文切换

4.1、进程上下文切换

在进程上下文切换过程中,操作系统需要完成以下操作:

  • 保存当前进程的上下文(如寄存器状态、程序计数器等)
  • 加载新进程的上下文
  • 更新内存管理单元(MMU)以映射新进程的地址空间
  • 切换到新进程的执行环境

4.2、线程上下文切换

线程跟进程的区别在于:线程是依赖于进程存在,线程是调度的基本单位,进程为线程提供虚拟内存,全局变量等资源。
简单来说:

  • 当进程只有一个线程时,可以认为进程就等于线程。
  • 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的。
  • 另外,线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的。

那么线程上下文切换就可以分为两种情况:

  1. 线程属于同一个进程,由于属于同一个进程,那么虚拟内存等资源不需要切换,只需要切换线程的私有资源,例如栈、寄存器等资源即可。
  2. 线程属于不同进程,这个时候切换过程跟进程上下文切换没有区别。

也就是说,在同一进程内线程上下文切换的代价是比进程切换小的。

4.3、系统调用上下文切换

我们知道,操作系统把进程的运行空间分为内核空间和用户空间。
图片

  • 其中操作系统运行在 内核空间(也叫内核态)(Ring 0)具有最高权限,可以直接访问所有资源;
  • 而用户写的代码运行在 用户空间(也叫用户态)(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,然后由内核代码去访问,再把结果返回。

   也就是说进程即可以运行在用户态,也可以运行在内核态,当调用系统函数时就会从用户态转入内核态,调用结束时就会从内核态转入用户态。那么这个转换过程会涉及上下文切换吗?
   答案是肯定的,因为操作系统的代码最终也是需要CPU去执行的,那么肯定需要寄存器和程序计数器的参与,那么就需要把用户写的代码从这两个地方“踢出去”,换成操作系统的代码,等操作完成了又需要把操作系统的代码从这两个地方“踢出去”,换成用户代码。也就是说一次系统调用导致了两次上下文切换。
   但是由于这个时候本质上还是属于同一进程,所以虚拟内存(MMU,TLB),全局变量等资源是不需要替换的。
   所以系统调用导致的上下文切换代价也比进程上下文切换的代价低。

4.4、中断上下文切换

    在前面的文章[Linux是怎么从网络上接收数据包的](https://mp.weixin.qq.com/s?__biz=Mzk0NjQ5ODY5OQ==&mid=2247484261&idx=1&sn=5a4a2fa9f56990b758ea4b8d70fdd842&chksm=c3047e81f473f79700dbad1cf126aa0311b396efb05134169149efa78e703a51e00ed03d1805&token=944685945&lang=zh_CN&scene=21#wechat_redirect)中我们有详细解释过中断的概念,中断在操作系统中拥有最高优先级,当发生中断时,需要停止当前进程的远行,优先处理中断。那么这个过程就需要把进程的上下文保存,等处理完中断后再次运行该进程的时候,就可以从上次暂停的地方继续运行。  
    中断上下文切换也与进程上下文切换不同,中断执行程序通常也是操作系统内核的一部分,并不涉及到进程的用户态。所以中断上下文切换也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。只需要切换CPU寄存器,程序计数器等资源。

五、怎么观察上下文切换次数

    通过上面的描述,我们知道了上下文切换涉及到寄存器,程序计数器,虚拟内存等资源的保存和恢复,这些操作必然是需要时间的。如果程序耗费在这些地方的时间变多了,那么性能肯定就会变差,接下来我们就来看看如何观察上下文切换耗费的时间。  
    vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。  

vmstat输出格式如下,总体分为四部分:

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  1      0 8693200 707820 4257088    0    0     0     7    0    0  1  1 99  0  0
 0  0      0 8692860 707820 4257156    0    0     0    60 2043 3710  1  1 98  0  0
 0  0      0 8696820 707820 4257140    0    0     0    46 2024 3688  0  0 99  0  0
system
in每秒的系统中断数,包括时钟中断。
cs每秒上下文切换的次数

这里我们主要关注in和cs。
vmstat 只给出了系统总体的上下文切换情况,要想查看每个进程的详细情况,可以使用pidstat。

pidstat -w

18:25:31      UID       PID   cswch/s nvcswch/s  Command
18:25:36        0       215      0.21      0.00  agent
18:25:36        0       275      0.84      0.21  base
18:25:36        0       456    103.35      0.00  cmlb_client
18:25:36        0       470     10.48      0.00  monitor_agent
18:25:36        0      2069      1.47      0.00  datawalker_logb
18:25:36        0   1060290      0.21      0.00  pidstat

重点关注:

  • cswch:表示每秒自愿上下文切换的次数,指的是进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。
  • nvcswch:表示每秒非自愿上下文切换的次数。指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。

六、上下文切换过多的影响

这里使用github上的一段代码测试「CPU 密集型任务」在不同线程数下的耗时情况。代码地址:https://github.com/nickliuchao/threadpollsizetest
图片

  • 横坐标为线程数
  • 纵坐标为耗时,单位ms

从上图可知,当线程数量太小,同一时间大量请求将被阻塞在线程队列中排队等待执行线程,此时 CPU 没有得到充分利用;当线程数量太大,被创建的执行线程同时在争取 CPU 资源,又会导致大量的上下文切换,从而增加线程的执行时间,影响了整体执行效率。
同时并发编程网也提供了另一种测试方式:https://ifeve.com/java-context-switch/

推荐阅读

1、原来阿里字节员工简历长这样
2、一条SQL差点引发离职
3、MySQL并发插入导致死锁


如果你也觉得我的分享有价值,记得点赞或者收藏哦!你的鼓励与支持,会让我更有动力写出更好的文章哦!
更多精彩内容,请关注公众号「云舒编程」

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

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

相关文章

天童美语开学季|开启“热辣滚烫”的新学期

新学期伊始,孩子们即将踏入一个充满挑战和机遇的学习环境。在这个关键时刻,学校和家庭需要更加紧密地协调合作,以确保孩子们能够得到充分的支持和帮助,顺利成长。    在假期生活分享中开启新学期第一课      寒假里孩子们…

深度学习 精选笔记(12)卷积神经网络-理论基础2

学习参考: 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增),以达到集多方教程的精华于一文的目的。 ③非常推荐上面(学习参考&#x…

【leetcode】二叉树的前序遍历➕中序遍历➕后序遍历

大家好,我是苏貝,本篇博客带大家刷题,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 1. 二叉树的前序遍历2. 二叉树的中序遍历3. 二叉树的后序遍历 1. 二叉树的前序遍历 点击查看题目 根…

保护IP地址安全:维护网络安全

在今天的数字化时代,IP地址是互联网通信的基础,也是网络安全的重要组成部分。保护IP地址安全至关重要,因为恶意攻击者可能利用IP地址进行网络入侵、数据泄露、服务拒绝等攻击。因此,制定有效的保护措施,维护IP地址的安…

【算法】火柴排队(离散化、归并排序)

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为: ∑i(ai−bi)^2,其中 ai 表示第一列火柴中第 i个火柴…

网络工程师之路由交换协议篇

网络工程师之路由交换篇 路由交换静态路由RIPOSPFISISBGP 以下均为个人笔记,摘录到csdn做备份 路由交换 路由 优先级 RIP 100 OSPF ASE 150 OSPF NSSA 150 IBGP 255 EBGP 255 IS-IS 15 OSPF 10 静态 60 默认开销是0 路由算法类型 D-V: 距离矢量算法 RI…

正信晟锦:老板拖工资怎么说比较合适

在职场中,老板拖欠工资是一个敏感而棘手的问题。面对这一情况,员工应保持冷静与专业,采取合适的方式表达自己的合理关切,并寻求问题的解决。 私下与老板进行沟通。选择一个适当的时机,以尊重和理解的态度开场&#xff…

【小黑送书—第十三期】>>《ARM汇编与逆向工程 蓝狐卷 基础知识》(文末送书)

与传统的CISC(Complex Instruction Set Computer,复杂指令集计算机)架构相比,Arm架构的指令集更加简洁明了,指令执行效率更高,能够在更低的功耗下完成同样的计算任务,因此在低功耗、嵌入式等领域…

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+HLS多路视频融合叠加,提供1套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放HLS多路视频拼接应用本方案的SDI接收OSD多路视频融合叠加应用本方案的S…

Unity中PICO中手柄按键返回值

文章目录 前言一、我们看一下每个按键返回值获取按键返回值的方法 二、我们实现一个左摇杆控制平滑移动的功能1、创建一个左摇杆控制移动的脚本2、传入XR Origin对象,并且定义一个公开变量控制移动速度3、获取到摇杆是否移动,以及移动的偏移量4、如果摇杆…

一个简单的Vue2例子讲明白拖拽drag、移入dragover、放下drop的触发机制先后顺序

几个小细节说明: 执行顺序dragstart→dragover→drop被拖拽的物体必须要设置draggable"true"(实际上只需要draggable就可以了,默认就是true),否者默认一般是不允许被拖拽的(图片除外)…

WEB前端 HTML 列表表格

列表 有序列表 使用“ol”创建“有序列表”&#xff0c;使用“li”表示“列表项” <body><ol type"1"><li>列表1</li><li>列表2</li><li>列表3</li></ol><ol type"A"><li>列表A<…

GaussDB数据库的索引管理

目录 一、引言 二、GaussDB数据库中的索引基本概念 1. 什么是GaussDB索引&#xff1f; 2. GaussDB索引的作用 三、GaussDB支持的索引类型 1. B-Tree索引 2. GIN索引 3. GiST索引 4. SP-GiST索引 四、创建和管理GaussDB索引 1. 创建索引 2. 删除索引 3. 索引的优化…

‍掌握SQL魔法:用`ORDER BY RAND()`随机化返回你的SQL查询结果!

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

Redis实现分布式锁源码分析

为什么使用分布式锁 单机环境并发时&#xff0c;使用synchronized或lock接口可以保证线程安全&#xff0c;但它们是jvm层面的锁&#xff0c;分布式环境并发时&#xff0c;100个并发的线程可能来自10个服务节点&#xff0c;那就是跨jvm了。 简单分布式锁实现 SETNX 格式&…

多行业万能预约门店小程序源码系统 带完整的搭建教程以及安装代码包

在数字化转型的大趋势下&#xff0c;门店预约服务已经成为提升客户体验、优化资源配置的关键环节。然而&#xff0c;市面上的预约系统往往功能单一&#xff0c;难以满足多行业的需求。小编给大家分享一款多行业万能预约门店小程序源码系统。该系统不仅具备高度的可定制性&#…

图文并茂!在Oracle VM VirtualBox上安装Ubuntu虚拟机的详细步骤指南

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

【php基础】输出、变量、

php基础补充 1. 输出2.和"的区别3.变量3.1变量的命名规则3.2 两个对象指向同一个值3.3 可变变量 4.变量的作用域5. 检测变量 1. 输出 echo: 输出 print: 输出&#xff0c;输出成功返回1 print_r(): 输出数组 var_dump(): 输出数据的详细信息&#xff0c;带有数据类型和数…

python-redis缓存装饰器

目录 redis_decorator安装查看源代码使用 redis_decorators安装查看源代码\_\_init\_\_.pycacheable.py 各种可缓存的类型cache_element.py 缓存的元素caching.py 缓存主要逻辑 使用 总结全部代码参考 redis_decorator 安装 pip install redis_decorator查看源代码 from io …

【LeetCode热题100】 226. 翻转二叉树(二叉树)

一.题目要求 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 二.题目难度 简单 三.输入样例 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;…