为啥 CFS 调度器使用红黑树?

Posted

技术标签:

【中文标题】为啥 CFS 调度器使用红黑树?【英文标题】:Reason why CFS scheduler using red black tree?为什么 CFS 调度器使用红黑树? 【发布时间】:2016-01-16 10:11:09 【问题描述】:

CFS 调度程序根据最小虚拟时间选择下一个进程,并使用红黑树 (rbtree) 有效地获取该值,使用 rbtree 我们将获得最小 O(h) 这里 h 是 rbtree 的高度。但是,使用最小堆,我们只能在 O(1) 时间内获得最小虚拟时间进程。我只想知道为什么在 CFS 实现中不考虑 min-heap 并且在内核级别使用 min-heap 是否有任何困难?

【问题讨论】:

我不是算法专家,但似乎在 o(1) peek 之后您应该执行 heapify(即 o(log n))来恢复堆属性。因此,如果我错了,请参考您所说的实现 【参考方案1】:

另一个有趣的点是,考虑到您有一个任务(进程或线程)将状态从可运行更改为阻塞(等待 io 或网络资源),那么您需要从运行队列中删除该任务 复杂性是:

红黑树的 O(log(n)) 堆的 O(n)

堆的移除操作很慢,所以红黑树比较好。

当我们得到最小 vruntime 时,堆操作实际上不是 O(1),只有当你引用根节点而不删除它时才会发生 O(1)。但在 CFS 中,我们需要

删除它(这需要 O(log(n)) 的堆积) 更新 vruntime,并将其插入回运行队列,这也需要 O(log(n))

【讨论】:

是的。这可能是另一个可能的原因!【参考方案2】:

原因是:堆是基于数组的,因此需要内核空间中的连续内存。这是因为堆在 Linux 中的实现方式。查看文件lib/prio_heap.cinclude/linux/prio_heap.h,您会注意到堆是kmalloc 使用heap_init。一旦多道程序空间变得巨大,维护数千个struct sched_entity 需要大量的连续空间(它在几个页面中运行)。从时间和性能的角度来看,人们更喜欢堆,因为一旦选择了 min vruntime,hepify 操作就可以在后台运行,但它的空间需求会造成瓶颈。

由于rbtree 很容易获得,内核开发人员并没有想到实现基于指针的堆,实际上也不需要。

【讨论】:

谢谢。这是我发现的唯一解释,它实际上给出了 rbtree 相对于堆的优势。其他的解释都说它们具有相同的时间复杂度。

以上是关于为啥 CFS 调度器使用红黑树?的主要内容,如果未能解决你的问题,请参考以下文章

读rbtree

读rbtree

为啥Linux CFS调度器没有带来惊艳的碾压效果? CSDN博文精选

Linux 内核CFS 调度器 ② ( CFS 调度器 “ 权重 “ 概念 | CFS 调度器调度实例 | 计算进程 “ 实际运行时间 “ )

Linux 内核CFS 调度器 ① ( CFS 完全公平调度器概念 | CFS 调度器虚拟时钟 Virtual Runtime 概念 | 四种进程优先级 | 五种调度类 )

CFS Scheduler(CFS调度器)