被神话的Linux, 一文带你看清Linux在多核可扩展性设计上的不足(4)
我们看到,在模拟微内核的代码中,用多线程执行并行访问共享数据curr时,开销不会随着线程数量的变化而变化,而模拟宏内核的代码中,总时间随着线程数的增加而线性增加,显然,这部分开销是自旋锁的开销。当今流行的CPU cache结构已经排队自旋锁的开销符合这种线性增长。 那么为什么微内核的模拟代码中的锁开销没有随着线程数量的增加而增加呢? 因为在类似宏内核的同步任务中,由于并发上下文的相互隔离,整个任务必须被一个锁保护,比如 Linux内核的tcp_v4_rcv 里面的:
然而,在微内核的代码中,类似上面的任务被打包统一交给单独的服务线程去 调度执行 了,大大减少了锁区里的延时。 宏内核的隔离上下文并发抢锁场景需要锁整个任务,造成抢锁开销巨大,而微内核只要锁任务队列的入队出队操作即可,这部分开销和具体任务无关,完全可预期的开销。 接下来让我们对比一下执行同样的任务,在不同CPU数量的约束下,两种模式的时间开销对比图: 可见,随着CPU数量的增加,模拟宏内核的代码锁开销大致在线性增加,而模拟微内核的代码,锁开销虽然也有所增加,但显然并不明显。 为什么会这样?请看下面宏内核和微内核的对比图,先看宏内核: 再看微内核: 这显然是一种更加 现代 的方式,不光是减小了锁的开销提高了性能,更重要的是大大减少了CPU的空转,提高了CPU的利用率。 我们先看一下模拟宏内核的代码在执行10秒时的CPU利用率: 观察下热点,可以猜测就是spinlock: 显然,CPU利用率那么高,并非真的在执行有用的task,而是在spin空转。 我们再看下模拟微内核的代码在同样情况下的表现: 看下热点: 显然,仍然有个spinlock的热点,但显然降低了很多。在更高执行效率的保证下,CPU并没有那么高,剩余的空闲时间可以再去执行更多有意义的工作进程。 本文只是展示一个定性的效果,实际中,微内核服务进程的任务队列的管理效率会更高。甚至可以硬件实现。【参见交换机背板的交换网络实现。】 (编辑:ASP站长网) |