1 BIO(阻塞IO)
阻塞IO就是两个阶段都必须阻塞等待
通常IO操作都是阻塞I/O的,也就是说当你调用read时,如果没有数据收到,那么线程或者进程就会被挂起,直到收到数据。
read直到数据复制到应用进程的缓冲区或者发生错误才会返回,这就是阻塞的定义:等待某个事件。
2 NIO(非阻塞IO)
非阻塞IO的recvfrom操作会理解返回结果而不是阻塞用户进程,
好处:如果等待的事件没有发生,如上图中所示的read数据未准备好,系统调用会立即返回而不是导致调用进程被挂起。
坏处:盲轮询(盲等)并没有提升性能,用户进程需要采用轮询的方式(逐个查找)查看事件状态,这往往耗费大量的CPU资源。
3 IO多路复用
无论是阻塞IO还是非阻塞IO,用户应用在一阶段都需要调用recvfrom来获取数据,差别在于无数据时的处理方案:
- 如果调用recvfrom时,恰好
没有
数据,阻塞IO会使进程阻塞,非阻塞IO使CPU空转,都不能充分发挥CPU的作用 - 如果调用recvfrom时,恰好
有
数据,用户进程可以直接进入第二阶段,读取并处理数据
比如服务端处理客户端Socket请求时,在单线程情况下,只能依次处理每一个socket,如果正在处理的socket恰好未就绪(数据读取不可读或不可写),线程就会被阻塞,所有其他客户端socket都必须等待,性能自然会很差
文件描述符:简称FD,是一个从 0 开始递增的无符号整数,用来关联Linux中的一个文件。在Linux中,一切皆文件,例如常规文件、视频、硬件设备等,当然也包括网络套接字(Socket)
IO多路复用:是利用单个线程来同时监听多个FD,并在某个FD可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源
recvfrom只能监听一个FD
select可以监听多个FD
不通过监听FD的方式、通知的方式又有多种实现,常见的有
- select
- poll
- epoll
区别:
- select和poll只会通知用户进程有FD就绪,但不确定具体是哪个FD就绪,但不确定具体是哪个FD,需要用户进程逐个遍历FD来确认
- epoll则会在通知用户进程FD就绪的同时,把已就绪的FD写入用户空间