IO多路复用的理解/演变过程( 三 )


文章插图
总结一下 。一切的开始,都起源于这个 read 函数是操作系统提供的,而且是阻塞的,我们叫它 阻塞 IO 。
为了破这个局,程序员在用户态通过多线程来防止主线程卡死 。
后来操作系统发现这个需求比较大 , 于是在操作系统层面提供了非阻塞的 read 函数,这样程序员就可以在一个线程内完成多个文件描述符的读取,这就是 非阻塞 IO 。
但多个文件描述符的读取就需要遍历,当高并发场景越来越多时,用户态遍历的文件描述符也越来越多,相当于在 while 循环里进行了越来越多的系统调用 。
后来操作系统又发现这个场景需求量较大,于是又在操作系统层面提供了这样的遍历文件描述符的机制,这就是 IO 多路复用 。
多路复用有三个函数,最开始是 select,然后又发明了 poll 解决了 select 文件描述符的限制,然后又发明了 epoll 解决 select 的三个不足 。
所以,IO 模型的演进,其实就是时代的变化,倒逼着操作系统将更多的功能加到自己的内核而已 。
如果你建立了这样的思维,很容易发现网上的一些错误 。
比如好多文章说,多路复用之所以效率高 , 是因为用一个线程就可以监控多个文件描述符 。
这显然是知其然而不知其所以然,多路复用产生的效果 , 完全可以由用户态去遍历文件描述符并调用其非阻塞的 read 函数实现 。而多路复用快的原因在于,操作系统提供了这样的系统调用,使得原来的 while 循环里多次系统调用,变成了一次系统调用 + 内核层遍历这些文件描述符 。
就好比我们平时写业务代码,把原来 while 循环里调 http 接口进行批量,改成了让对方提供一个批量添加的 http 接口 , 然后我们一次 rpc 请求就完成了批量添加 。

推荐阅读