引入背景
阻塞式I/O的弊端:传统的阻塞式I/O模型中,进程一旦进行I/O读写就会阻塞,导致整个系统的吞吐量急剧下降。为了处理多个I/O操作,可能需要创建大量的线程或进程,但这会带来线程或进程切换的开销,浪费CPU资源。
多路复用的概念
多路复用(I/O Multiplexing):同时监视多个文件描述符(文件句柄),当某个文件描述符就绪(一般是读写就绪)时,就通知程序进行相应的操作。
select的实现原理
-
位图机制:select使用位图来跟踪需要监视的文件描述符的状态变化。总共有三种位图,分别对应于可读、可写和异常事件。
-
用户注册:用户程序预先将socket文件描述符注册至读、写、异常位图。
-
系统调用:通过select系统调用来轮询位图中的socket的读、写、异常事件。
-
内核处理:内核底层通过轮询方式检测位图中注册的socket文件事件。如果检测到有socket文件处于就绪状态,则将该socket对应的事件设置到输出位图。
-
结果返回:所有位图中的socket都被轮询完后,内核将输出位图通过copy_to_user函数复制到用户态的输入位图,并覆盖用户初始化的位图信息。
-
超时处理:如果未检测到任何socket文件处于就绪状态,则根据设置的超时时间确定是否返回或阻塞进程。
直白总结
select的本质是将判断某个文件描述符(TCP中通常是socket,因为多个客户端和服务器通信,服务器就需要建立多个socket)是否处于就绪状态(就绪状态是指socket进入可读、可写、异常的某一种状态(比较重要),也有地方描述为socket可以进行IO操作的状态)的工作交给后台,这个时间你可以去处理其它的事情,等后台处理完了返回给你一个新的就绪状态的文件描述符集,你就可以接着处理这些处于就绪状态的socket连接。
直白总结2
select会将应用层文件描述符集以位图形式拷贝到内核,内核处理完后会将改变的文件描述符集返回给应用层。
优缺点
优点:可以同时处理多个连接,避免了大量的线程或进程切换,提高了系统的并发性能。
缺点:在大量文件描述符的情况下,select的性能会受到限制,因为它需要轮询所有的文件描述符。此外,由于select使用位图来存储文件描述符,因此文件描述符的集合大小是有限制的。
替代技术(会再有新的篇章)
poll:与select类似,但克服了select的一些限制,如文件描述符集合的大小。但poll在大量文件描述符的情况下性能仍然不佳。
epoll:Linux特有的I/O多路复用技术,使用事件驱动的方式,当文件描述符就绪时,会触发相应的事件,从而避免了轮询的开销。epoll在大量文件描述符的情况下性能更好。