前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >总说上下文切换耗性能,那他到底耗了多少性能?

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

作者头像
公众号 云舒编程
发布2024-03-13 08:37:58
1170
发布2024-03-13 08:37:58
举报
文章被收录于专栏:图解系列图解系列

一、前言

   众所周知,操作系统是一个分时复用系统,通过将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):通过虚拟内存和物理内存的映射,使的每个程序都认为自己可以使用完整的内存。详细解释:baike.baidu.com/item/MMU/45…

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

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

4.1、进程上下文切换

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

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

4.2、线程上下文切换

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

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

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

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

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

4.3、系统调用上下文切换

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

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

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

4.4、中断上下文切换

在前面的文章Linux是怎么从网络上接收数据包的中我们有详细解释过中断的概念,中断在操作系统中拥有最高优先级,当发生中断时,需要停止当前进程的远行,优先处理中断。那么这个过程就需要把进程的上下文保存,等处理完中断后再次运行该进程的时候,就可以从上次暂停的地方继续运行。 中断上下文切换也与进程上下文切换不同,中断执行程序通常也是操作系统内核的一部分,并不涉及到进程的用户态。所以中断上下文切换也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。只需要切换CPU寄存器,程序计数器等资源。

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

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

代码语言:javascript
复制
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。

代码语言:javascript
复制
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 密集型任务」在不同线程数下的耗时情况。代码地址:github.com/nickliuchao…

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、进程是什么
    • 2.1、进程资源
    • 三、上下文切换到底在切换什么?
    • 四、有哪些类型的上下文切换
      • 4.1、进程上下文切换
        • 4.2、线程上下文切换
          • 4.3、系统调用上下文切换
            • 4.4、中断上下文切换
            • 五、怎么观察上下文切换次数
            • 六、上下文切换过多的影响
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档