文章目录

  • 什么是上下文切换
  • 进程上下文切换
  • 线程上下文切换
  • 中断上下文切换
  • 如何减少上下文切换
  • 来个例子亲身感受下

什么是上下文切换

  在多任务操作系统中,为了提高CPU的利用率,可以让当前系统运行远多于CPU核数的线程。但是由于同时运行的线程数是由CPU核数来决定的,所以为了支持更多的线程运行,CPU会把自己的时间片轮流分给其他线程,这个过程就是上下文切换
  导致上下文切换的原因有很多,比如通过wait()、sleep()等方法阻塞当前线程,这时CPU不会一直等待,而是重新分配去执行其他线程。当后续CPU重新切换到当前线程时,CPU需要沿着上次执行的指令位置继续运行。因此,每次在CPU切换之前,需要把CPU寄存器和程序计数器保存起来,这些信息会存储到系统内核中,CPU再次调度回来时会从系统内核中加载并继续执行。简而言之,上下文切换,就是CPU把自己的时间片分配给不同的任务执行的过程

根据任务类型的不同,上下文切换又分为三种类型:

 ●进程上下文切换。●线程上下文切换。●中断上下文切换。

进程上下文切换

进程上下文切换,是指当前进程的CPU时间片分配给其他进程执行,进程切换有以下三种情况:

 ●CPU时间片分配。●当进程系统资源(如内存)不足时,进程会被挂起。●当存在优先级更高的进程运行时,当前进程有可能会被挂起,CPU时间片分配给优先级更高的进程运行。

  进程的上下文切换和线程的上下文切换相同,进程切换之后,再恢复执行时,还是需要沿着上一次执行的位置继续运行,但是与线程相比,进程的上下文切换的损耗会更大。
  原因是进程在做上下文切换时,需要把用户空间中的虚拟内存、栈、全局变量等状态保存起来,还需要保存内核空间的内核堆栈、寄存器等状态(之所以要保存内核态的状态信息,是因为进程的切换只能发生在内核态)。同时在加载下一个进程时,需要再次恢复上下文信息,而这些操作都需要在CPU上运行。

  每次进程的上下文切换需要几纳秒或几微秒的CPU时间,从我们的感官上看起来好像不算很长,但是如果进程上下文切换次数非常多,就会导致CPU把大量的时间耗费在寄存器、内核栈、虚拟内存、全局变量等资源的保护和恢复上,使得CPU真正工作的时间很少,这也是为什么我们常说上下文切换过于频繁会影响性能。
  现在,相信读者能够理解为什么要设计线程,因为线程的上下文切换对资源的保存和恢复占用更少,从而使得线程的上下文切换的时间更短。

线程上下文切换

  线程就是轻量级进程,它们最大的区别是,进程是CPU调度的最小单元,而线程是系统资源分配的基本单元。一个 进程中允许创建多个线程,这些线程可以共享同一进程中的资源。

  线程上下文切换需要注意两点:

 ●当两个线程切换属于不同的进程时,由于进程资源不共享,所以线程的切换其实就是进程的切换。●当两个线程属于同一个进程时,只需要保存线程的上下文。

  线程的上下文切换,需要保存上一个线程的私有数据、寄存器等数据,这个过程同样会占用CPU资源,当上下文切换过于频繁时,会使得CPU不断进行切换,无法真正去做计算,最终导致性能下降。

中断上下文切换

  中断上下文切换是指CPU对系统发生的某个中断事件做出反应导致的切换,比如:

 ●CPU本身故障、程序故障。●I/O中断。

  为了快速响应硬件事件,中断处理会打断当前正常的进程调度和执行过程,此时CPU会调用中断处理程序响应中断事件。而这个被打断的进程在切换之前需要保存该进程当前的运行状态,以便在中断处理结束后,继续恢复执行被打断的进程。这里不涉及用户态中的资源保存,只需要包含内核态中必需的状态保存,如CPU寄存器、内核堆栈等资源。即便如此,中断导致的上下文切换仍然会消耗CPU资源。

如何减少上下文切换

  既然频繁的上下文切换会影响程序的性能,那么如何减少上下文切换呢?

●减少线程数, 同一时刻能够运行的线程数是由CPU核数决定的,创建过多的线程,就会造成CPU时间片的频繁切换。

●采用无锁设计解决线程竞争问题,比如在同步锁场景中,如果存在多线程竞争,那么没抢到锁的线程会被阻塞,这个过程涉及系统调用,而系统调用会产生从用户态到内核态的切换,这个切换过程需要保存上下文信息对性能的影响。如果采用无锁设计就能够解决这类问题。

●采用CAS自旋操作,它是一种无锁化的编程思想,原理是通过循环重试的方式避免线程的阻塞导致的上下文切换。

  总的来说,CPU的切换本意是为了提高CPU的利用率,但是给过多的CPU上下文切换,会使CPU把时间都消耗在上下文信息的保存和恢复上,从而使真正的有效执行时间缩短,最终导致整体的运行效率大幅下降。

来个例子亲身感受下

遍历一个比较大的数字,多大呢,100000000 可以吧?

public class ThreadConcurrentExample implements Runnable{private static final Long num=100000000L;private int sum;public ThreadConcurrentExample(int sum) {this.sum=sum;}public static void runWithThread() throws InterruptedException {long start=System.currentTimeMillis();//执行两个任务//1. 计算指定目标数的和int tempSum=0;ThreadConcurrentExample tce=new ThreadConcurrentExample(tempSum);Thread thread=new Thread(tce);thread.start();//2.同步计算遍历次数int count=0;for (int i = 0; i < num; i++) {count++;}thread.join(); //确保线程执行结束long totalFree=System.currentTimeMillis()-start;//打印耗时System.out.println("runWithThread: totalFree="+totalFree+",count="+count);}public static void runWithSerial() throws InterruptedException {long start=System.currentTimeMillis();//执行两个任务//1. 计算指定目标数的和int tempSum=0;for (int i = 0; i < num; i++) {tempSum+=i;}//2.同步计算遍历次数int count=0;for (int i = 0; i < num; i++) {count++;}long totalFree=System.currentTimeMillis()-start;//打印耗时System.out.println("runWithSerial: totalFree="+totalFree+",count="+count);}@Overridepublic void run() {for (int i = 0; i < num; i++) {//            synchronized (this) {sum += i;//先用无锁感受下速度
//            }}}public static void main(String[] args) throws InterruptedException {runWithThread();runWithSerial();}
}

结果如下:

针对sum+=i这个操作,由于不是原子的,所以线程不安全,我们增加一个锁,将run()方法的注释打开

    public void run() {for (int i = 0; i < num; i++) {synchronized (this) {sum += i;//加上锁}}}


  可以看到,增加同步锁之后,采用多线程执行的任务运行时长增加了20多倍。原因是增加synchronized锁会导致线程去竞争锁,这个竞争的过程会导致线程的上下文切换。即便不增加synchronize锁,当线程的创建数量远远超过CPU核数时,也会因为上下文切换导致性能下降。
  利用我们掌握的知识,导致线程上下文切换的原因总结如下:

 ●多个任务抢占synchronized同步锁资源。●在线程运行过程中存在IO阻塞,CPU调度器会切换CPU时间片。●在线程中通过主动阻塞当前线程的方法释放CPU时间片。●当前线程执行完成后释放CPU时间片,CPU重新调度。

  实际上,对于上下文切换次数,在Linux中可以使用vmstat命令来查看,vmstat 命令是Linux中比较常见的针对CPU、内存等信息的监控工具,下面是笔者利用vmstat命令打印的生产服务器的监控信息。

vmstat1表示每隔ls打印一次数据。

在上述打印结果中,有一个cs (Content Switch)字段,它表示每秒上下文切换的次数,这个值越小越好,如果过大,就要考虑降低线程或进程的数量。

理解上下文切换带来的性能影响相关推荐

  1. 一起谈.NET技术,.Net Discovery系列之-深入理解平台机制与性能影响 (中)

    上一篇文章中Aicken为大家介绍了.Net平台的垃圾回收机制与其对性能的影响,这一篇中将继续为大家介绍.Net平台的另一批黑马-JIT.有关JIT的机制分析 ● 机制分析以C#为例,在C#代码运行前 ...

  2. .Net Discovery系列之十一-深入理解平台机制与性能影响 (中)

    上一篇文章中Aicken为大家介绍了.Net平台的垃圾回收机制与其对性能的影响,这一篇中将继续为大家介绍.Net平台的另一批黑马-JIT.    有关JIT的机制分析    ● 机制分析    以C# ...

  3. .Net Discovery系列之十二-深入理解平台机制与性能影响(下)

    上一篇文章中Aicken为大家介绍了.Net平台的垃圾回收机制.即时编译机制与其对性能的影响,这一篇中将继续为大家介绍.Net平台的异常捕获机制与字符串驻留机制. 三.关于异常捕获机制 虽然我们已经很 ...

  4. Redis 性能影响 - 内存碎片和缓冲区

    Redis 性能影响 - 内存碎片和缓冲区 一. 内存碎片带来的性能影响 1.1 内存碎片的形成 1.2 清理内存碎片 1.3 总结 二. 内存缓冲区溢出问题 2.1 客户端通信中的缓冲区 2.1.1 ...

  5. 盘点 Oracle 11g 中新特性带来的10大性能影响

    盘点 Oracle 11g 中新特性带来的10大性能影响 原创 2017-08-02 盖国强 数据和云 Oracle的任何一个新版本,总是会带来大量引人瞩目的新特性,但是往往在这些新特性引入之初,首先 ...

  6. GSO/TSO/GRO等对VirtIO虚机的网络性能影响分析(by quqi99)

    作者:张华  发表于:2016-04-05 版权声明:能够随意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) IP ...

  7. php ssd性能影响,SATA SSD有无缓存,是否影响速度性能实例

    原标题:SATA SSD有无缓存,是否影响速度性能实例 在前面一篇文章里我们通过为SATA SSD虚拟缓存的方法,证明了缓存对SATA SSD速度性能的影响不大. 一般消费级SSD的缓存都是采用的DD ...

  8. 内存容量对计算机运行影响大吗,探索内存容量对基础应用的性能影响有多大

    前段时间,我们针对内存容量对游戏性能的影响做了系统的探究--硬糖:探索内存容量对整机游戏性能影响有多大?那么,在应用范围更加广泛的日常工作中?不同容量,单通道.双通道内存是否也会也有着极大的性能差别呢 ...

  9. 39 | 案例篇:怎么缓解 DDoS 攻击带来的性能下降问题?

    上一节,学习了 tcpdump 和 Wireshark 的使用方法,并通过几个案例,带你用这两个工具实际分析了网络的收发过程.碰到网络性能问题,不要忘记可以用 tcpdump 和 Wireshark ...

  10. 深入解析:Row Movement 的原理和性能影响与关联

    作者简介: 黄玮(Fuyuncat) 资深Oracle DBA,个人网站www.HelloDBA.com,致力于数据库底层技术的研究,其作品获得广大同行的高度评价. ROW MOVEMENT特性最初是 ...

最新文章

  1. 一般筛法求素数+快速线性筛法求素数
  2. UCLA教授遭到举报后被停课!原因竟是不同意学生主张的“考试放水”
  3. java实验四云南大学_云南大学JAVA程序设计实验四
  4. 昨天服务器出现问题,解决过程如下所述
  5. oracle的cols,Oraclecols_as_rows比对数据
  6. python实习目的_python爬虫系列---为什么要学习爬虫
  7. HDU1582 AC Again【DFS】
  8. AI 框架部署方案之模型转换
  9. centos6.2安装office及PDF阅读器
  10. 人工智能在日常生活中的十大应用
  11. Audacity分析浊音、清音、爆破音特点
  12. 如何在simlink仿真示波器中的波形上取几个点?
  13. vue2.x+antd-vue搭建后管项目
  14. 如何取悦自己或者增加自己幸福感的方式
  15. echart 多种覆盖物 显示优先级
  16. 网络原理 | 网络设备及相关技术(集线器、交换机、主机、路由器)、冲突域与广播域
  17. win11安装SolidWorks激活时闪退,长时间无响应
  18. 使用Google百度等搜索引擎的常用搜索技巧
  19. 电晕放电和击穿空气有何区别?---气体放电管击穿放电
  20. maven-pom文件dependence标签

热门文章

  1. springboot/vue 前后端分离项目搭建流程
  2. java全栈工程师培训,分享面经
  3. 大图书馆 #5 纳瓦尔宝典
  4. java quartz 每月1号执行_Quartz 每月1号 执行规则表达式
  5. “确定“和“取消“摆放顺序
  6. c语言程序 实现简单计算器功能,C语言实现简单计算器功能(2)
  7. ros怎么跑小车_ROS与RACECAR教程-Arduino ROS节点进行小车控制
  8. 上线三年却很“鸡肋”的微信声音锁究竟做错了什么?
  9. Mysql 索引失效场景
  10. 如何决定是否参加培训,一个业内人士的推荐