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

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

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

关注公众号获取:
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 st0  1      0 8693200 707820 4257088    0    0     0     7    0    0  1  1 99  0  00  0      0 8692860 707820 4257156    0    0     0    60 2043 3710  1  1 98  0  00  0      0 8696820 707820 4257140    0    0     0    46 2024 3688  0  0 99  0  0
system
in每秒的系统中断数,包括时钟中断。
cs每秒上下文切换的次数

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

pidstat -w18: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并发插入导致死锁


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

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

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

相关文章

.NET高级面试指南专题十九【 数据库设计-4范式】

数据库范式设计是关系数据库设计中的重要概念,旨在减少数据冗余和提高数据的一致性。 范式设计的目的是提高数据库的数据质量、一致性和可维护性。通过将数据结构化为不同的范式,可以降低数据冗余,减少数据更新异常,提高数据的可靠…

Java八股文(MyBatis Plus)

Java八股文のMyBatis Plus MyBatis Plus MyBatis Plus MyBatis Plus 是什么?它与 MyBatis 有什么区别? MyBatis Plus 是基于 MyBatis 进行扩展的一款持久层框架,它提供了一系列增强功能,简化了 MyBatis 的使用。 与 MyBatis 相比…

C++学习基础版(一)

目录 一、C入门 1、C和C的区别 2、解读C程序 3、命名空间 4、输入输出 (1)cout输出流 (2)endl操纵符 (3)cin输入流 二、C表达式和控制语句 1、数据机构 特别:布尔类型bool 2、算数运…

处理Centos 7 中buff/cache高的问题

在CentOS 7中,如果发现 buff/cache 栏目的值过高占用了大量内存,可以尝试以下方法来释放部分缓存: 清理页面缓存 Linux内核会缓存最近使用过的内存页面,以提高访问速度。你可以使用以下命令清理页面缓存: sudo sync && sudo echo 1 > /proc/sys/vm/drop_caches …

Leetcode 3082. Find the Sum of the Power of All Subsequences

Leetcode 3082. Find the Sum of the Power of All Subsequences 1. 解题思路2. 代码实现 题目链接:3082. Find the Sum of the Power of All Subsequences 1. 解题思路 这一题的话其实反而还好,就是一个比较常规的动态规划的题目。 我们首先需要想明…

数据结构的基本框架以及泛型

目录 集合框架复杂度大O的渐进表示法 装包(箱)或者拆包(箱)装包拆包 泛型泛型的上界泛型方法求最大值 集合框架 Java的集合框架,Java Collection Framework 又被称为容器container, 定义在java.util包下的一组 interfaces 和其实现类 classes interface: 接口 abstracb class…

【LeetCode热题100】24. 两两交换链表中的节点(链表)

一.题目要求 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 二.题目难度 中等 三.输入样例 示例 1: 输入&am…

Docker 哲学 - 容器操作 (二)

命令行启动 参数键值之间可以使 " " 或者 空格 卷的挂载是在容器创建时指定的,不能在容器运行时再添加 当加上 --network-alias 设置同一网络下别名参数后 ,inspect 该容器发现 会同步到 容器信息中 2、给容器打日志 docker logs 【-…

深度学习_ResNet_5

ResNet学习目标 什么是ResNet为什么要引入ResNet?ResNet网络结构的特点利用ResNet完成图像分类 什么是ResNet? ResNet(Residual Network)是一种深度残差网络,由何凯明等人在2015年提出,是深度学习领域中一…

Leetcode 31. 删除无效的括号

心路历程: 一开始看到有点懵,后来发现有点像按照一定规则穷举所有可能情况,想到了排列组合问题,再结合问题长度不固定,无法用已知个for循环表示,从而想到了回溯。这个题相当于需要在一定规则下枚举。 按照…

力扣题目训练(22)

2024年2月15日力扣题目训练 2024年2月15日力扣题目训练563. 二叉树的坡度637. 二叉树的层平均值643. 子数组最大平均数 I304. 二维区域和检索 - 矩阵不可变154. 寻找旋转排序数组中的最小值 II 2024年2月15日力扣题目训练 2024年2月15日第二十二天编程训练,今天主要…

3月17日ACwing每日一题

1230. K倍区间 - AcWing题库 //超时写法 需要优化 //两个1e5嵌套 变成1e10了>1e8需要优化 #include <bits/stdc.h> using namespace std; const int N100007; int a[N]; int main(){int n,k;cin>>n>>k;for(int i1;i<n;i){cin>>a[i];a[i]a[i-1]…

web ui自动化测试--元素操作

一、介绍 什么是web ui自动化测试 1、通过代码来模拟人的手工操作,执行测试内容 2、自动化是为了代替重复的手工操作,提高测试效率 ui自动化的价值: 1、回归速度的对比,以前进行全量回归测试需要x天,现在有没有减少 2、负责功能测试的同事,是不是有更多的时间测试新需求…

Java面试题总结15之简述你对RPC,RMI的理解

RPC&#xff1a;在本地调用远程的函数&#xff0c;远程过程调用&#xff0c;可以跨语言实现&#xff0c;httpClient RMI&#xff1a;远程方法调用&#xff0c;Java中用于实现RPC的一种机制&#xff0c;RPC的Java版本是J2EE的网络调用机制&#xff0c;跨JVM调用对象的方法&…

Redis-2 Redis基础数据类型与基本使用

高级Redis应用进阶 一站式Redis解决方案-Redis-2 Redis基础数据类型与基本使用 源代码在GitHub - 629y/food-social-contact-parent: redis项目-美食社交APP 1. Redis基本数据类型 1.字符串&#xff08;strings&#xff09; set username zhangsan get username mset age 18 …

JAVA代理模式梳理

什么是代理模式 代理模式&#xff1a;为其他对象提供一种代理&#xff0c;用以控制对这个对象的访问&#xff1b; 我们使用代理对象&#xff0c;可以在不修改目标对象的基础上&#xff0c;增强主业务逻辑&#xff1b;比如说我们的系统中有一个登录接口&#xff0c;我们要对这个…

在数据对象中增加新的属性值,数据更新,视图不更新问题

一、原始数据 dataTable:[{aa:111} ]然后我需要再给他一个对象属性值&#xff0c;就会发现打印出来的数据是更新了&#xff0c;视图不更新&#xff0c;原因是在于在Vue实例创建时&#xff0c; dataTable.bb 并未声明&#xff0c;因此就没有被Vue转换为响应式的属性. this.dat…

ECMAscript6学习

ECMAscript6介绍 ECMA是一个浏览器脚本标准制定的公司&#xff0c;Netscape 创造了 JavaScript 由于商标原因&#xff0c; 后面ECMA公司取名ECMAscript 1 发布&#xff0c;JavaScript 也就是 ECMAscript.到现在最新的版本是6&#xff0c;简称es6. 新增let 与const let 与const …

【数据分析可视化】动态生成柱状图

import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as ticker from matplotlib.animation import FuncAnimation import matplotlib.patches as mpatches from matplotlib.animation import FFMpegWriter# 定义一个函数&#xff0c;用于生成…

探秘酒店业黑科技:3D可视化引领管理新风尚

在信息化飞速发展的今天&#xff0c;酒店管理已不再是传统的模式所能满足。 想象一下&#xff0c;你站在一个巨大的3D地图上&#xff0c;轻轻一点&#xff0c;就能瞬间进入酒店的任何一个角落。你可以看到客房的布置、餐厅的摆设、会议室的布局……一切都如同身临其境&#xff…