单核CPU上多线程未提速原因及调度相关问题咨询
问题解答
问题1:为什么多线程没有更快?我梳理的时间线存在什么问题?
你的时间线最大的问题是忽略了现代操作系统的组调度机制:主流OS(比如Linux、Windows)默认会以进程为单位分配CPU配额,同优先级的进程平分整机CPU资源,进程内部的多个线程再瓜分该进程拿到的总CPU配额。
也就是说,你开1个线程还是4个线程,整个进程能拿到的CPU总时长是固定的,和其他同优先级进程保持一致。你拆分出4个线程只是把你拿到的固定CPU时长分成了4份运行,总执行时间不会变短,反而会额外增加线程上下文切换、CPU缓存失效的开销,实际运行速度反而会更慢。
如果没有组调度,所有线程平级竞争CPU,那你开4个线程确实能拿到更多的CPU配额,运行速度会更快,不过这种调度策略会导致开多线程的进程恶意抢占CPU,对其他进程不公平,因此没有被通用操作系统采用。
问题2:前文提到的cycle节点的专业名称是什么?
通用的专业名称是调度周期(scheduling cycle),在Linux的CFS调度器中也叫sched_period,指调度器遍历完所有就绪线程一轮所需要的总时长。
问题3:调度周期是固定的还是各线程时间片之和?
不同调度器的实现逻辑不同,以当前应用最广的Linux CFS调度器为例:
- 当就绪线程数小于等于阈值(默认8个)时,调度周期是固定值(默认20ms),每个线程的时间片 = 调度周期 *(线程权重 / 所有就绪线程总权重),优先级越高的线程权重越大,拿到的时间片越长。
- 当就绪线程数超过阈值时,会先保证每个线程的最小时间片(默认1ms),此时总调度周期 = 就绪线程数 * 最小时间片,也就是所有线程时间片的总和,不再是固定值。
问题4:时间片是基于时间还是基于指令计数?
所有通用操作系统的时间片都是基于CPU实际运行时间统计的,不会使用指令计数。因为不同CPU指令的执行时钟周期差异极大,再加上流水线、乱序执行、缓存命中等因素的影响,指令计数完全无法公平衡量线程的CPU占用情况,只有基于时间的统计能保证调度公平性。只有极少数特定场景的实时操作系统会采用指令计数的时间片机制。
问题5:CPU利用率为什么不始终为100%?
你的判断是正确的。只有当CPU的就绪队列里始终有可运行的线程时,利用率才会达到100%。当所有线程都处于阻塞状态(等待I/O、锁、信号量、用户输入等事件),没有可运行的就绪线程时,CPU就会运行空闲(IDLE)线程,这部分时间不会被计入利用率,因此整体利用率就会下降。日常使用中大部分进程大部分时间都处于阻塞等待状态,因此CPU利用率通常都远低于100%。
内容的提问来源于stack exchange,提问作者Mahan Lamee

