- CPU 保存线程 A 用户态指令,切换为内核态
- 保存线程 A 私有资源(栈、寄存器...)
- 保存线程 A 用户态资源(虚拟内存、全局变量...)
- 加载线程 B 用户态资源(虚拟内存、全局变量...)
- 加载线程 B 私有资源(栈、寄存器...)
- CPU 恢复线程 B 用户态指令,切换回用户态
system time
,进而大大缩短了真正运行进程的 user time
。当用户线程过多时,会引起大量的上下文切换,导致不必要的性能开销 。
线程调度Linux 中的线程是从父进程
fork
出的轻量进程,它们共享父进程的内存空间 。Linux 的调度策略是抢占式的,每个线程都有优先级
prirority
的概念,并按照优先级高低分为两种:- 实时进程(优先级 0~99)
- 普通进程(优先级 100~139)
runqueue
,需要运行的线程会被加入到这个队列中 。文章插图
每个队列可以进一步细分为 3 个队列以及 5 种调度策略:
dl_rq
SCHED_DEADLINE
选择deadline
距离当前时间点最近的任务执行
rt_rq
—— 可以互相抢占的实时任务SCHED_FIFO
一旦抢占到 CPU 资源,就会一直运行直到退出,除非被高优先级抢占SCHED_RR
当 CPU 时间片用完,内核会把它放到队列末尾,可以被高优先级抢占
cfs_rq
—— 公平占用 CPU 时间的普通任务SCHED_NORMAL
普通进程SCHED_BATCH
后台进程
dl_rq
里选择任务,然后从 rt_rq
里选择任务,最后从 cfs_rq
里选择任务 。所以实时任务总是会比普通任务先得到执行 。实时进程的优先级总是高于普通进程,因此当系统中有实时进程运行时,普通进程几乎是无法分到时间片的 。
nice 值为了保证
cfs_rq
队列的公平性,Linux 采用完全公平调度算法 CFS Completely Fair Scheduler
进行调度,保证每个普通进程都尽可能被调度到 。CFS 引入了
vruntime
作为衡量是否公平的依据:vruntime
与任务占用的 CPU 时间成正比vruntime
与任务优先级成反比(优先级越高vruntime
增长越慢)
vruntime
较小,说明它以前占用 CPU 的时间较短,受到了不公平对待,因此该进程会被优先调度,从而到达所谓的公平性 。为了实现可控的调度,Linux 为普通进程引入了
nice
值的概念 。其的取值其范围是 -20 ~ +19
,调整该值会改变进程的优先级:prirority += nice
。与此同时
vruntime
计算也会受到影响:进程的 nice 值越小, 优先级越高, 所能分到的运行时间也越多当用户进程设置了一个大于 0 的 nice 值时,其用户态的运行时间将被统计为
nice time
而不是 user time
。简单来说,nice time
表示 CPU 花了多少时间用于运行低优先级的任务 。当
nice time
占比比较高时,通常是某些定时任务调度器导致的:它们会为后台任务进程设置一个较大的 nice
值,避免这些进程与其他线程争抢 CPU 资源 。
经验总结扩展阅读
- 工厂方法在Spring源码中的运用
- 啤酒度数怎么看
- OnionArch - 如何实现更新指定字段的通用Handler
- 关于三伏天出伏的诗有哪些 三伏天宜静还是宜动
- windows C++ 异常调用栈简析
- 宋嫂鱼羹的来历
- .NET平台下一个你不知道的框架,我只想说两个字:“牛逼”
- 胡辣汤是河南的吗
- 四伏天是几月 伏天晒背的最佳时间
- 不属于夏季节气的是