上下文切换是在做什么事情?
本质上来说无论是用户态还是内核态的上下文切换都是很轻量的,甚至有一些硬件指令来支持,比如pusha可以帮助我们保存通用寄存器。同一个进程的线程共享页表,因此上下文切换的开销一般只有:
-
保存各种寄存器
-
切换sp(call指令会自动将pc压栈)
可以在数十条指令内完成。
既然近内核以及上下文切换都不慢,那么多线程的开销究竟在哪?
我们不妨看一个阻塞的系统调用futex的热点分布:
参考:https://www.cnblogs.com/ck1020/p/6666298.html
https://blog.****.net/changexhao/article/details/78287730
可以看到上面的热点中有大量涉及调度的开销。我们来看过程:
-
调用系统调用(可能需要阻塞);
-
系统调用确实需要阻塞,kernel需要决定下一个被执行的线程(调度);
-
执行上下切换。
因此,上面2个误区与多线程的开销都有一定因果关系,但是真正的开销来源于线程阻塞唤醒调度。
综上,希望通过线程模型来提升web server性能的原则是:
-
活跃线程数约等于CPU个数
-
每个线程不太需要阻塞