I/O模型linux
Unix下共有五种I/O模型:服务器
1>:阻塞I/O网络
2>:非阻塞I/O多线程
3>:I/O多路复用异步
4>:信号驱动I/Osocket
5>:异步I/Oide
其中前四种是同步I/O模型,只有第五种是异步的。函数
同步与异步:spa
这里的同步和两个实体之间通讯中的同步的概念是不同的,这里的同步是指关于这个I/O中的一系列动做都须要本身来完成,不管你是原地等待事件的发生(阻塞)仍是当某个事件已经准备好的时候你去完成后面的的动做(非阻塞)都属于同步。线程
异步,它是指是调用另外一个执行者去完成,当执行者发现要处理的时间后调用你,你再完成这件事情,执行的过程和你的动做是不牵扯的。
阻塞与非阻塞:
阻塞是指,等待某个事件的发生,若是它没有发生则一直等待下去直到事件发生为止。
非阻塞,不须要死死的等待,当它有返回的时候再去处理。
1>阻塞I/O
使用的I/O函数,致使程序阻塞,等待数据,若是数据没有准备好则一直等待。
例如咱们使用的阻塞式的socket建立套接字的时候,调用accept/recvfrom/connect...等都会是阻塞式的等待链接,请求或者数据的到来
阻塞式的函数实现起来很简单,但它有不少的问题,首先做为一个网络的服务器,阻塞式的等待会浪费大量的资源和时间,当服务器调用函数sendto给远端的一个客户端发送数据时,这时候不作其余的事情那么日后的动做都堵塞在后面,这样显然是不合适的,解决这种问题的方法每每是建立一个进程或者线程去解决这件事,由于进程的开销远远地大于线程的开销,因此使用多线程的方法解决是很行得通的。
阻塞式的I/O的好处就是它很是的稳定,他能保证链接保证接受和发送数据的肯定性,这是大多大的互联网公司使用多线程的缘由,而且使用线程池也会大大增长线程开启的效率。
2>非阻塞式I/O
调用socket函数并将其设置为非阻塞模式,设置方式,linux下调用fcntl()函数。
非阻塞方式下,当前执行流再也不以睡眠的方式来等待请求或者数据的到来,而采用轮询的方式,这种方式的运做流程是这样的,每隔一个时间段便返回一次,若是有数据到来则返回,若是没有,则返回一个错误码WSAEWOULDBLOCK,咱们须要不断的用循环来等待数据的成功返回,这个过程每每会占用大量的CPU。
非阻塞的缺点,虽然他不用再使等待太僵硬,但它不可避免的一次只能等待一个事件的到来。
3>信号驱动I/O
在TCPsocket中发生如下事件均会产生SIGIO信号,由于在同一个时候产生这种信号的缘由太多咱们不能区分究竟是哪种状况产生的SIGIO信号,因此在TCP中信号驱动是不太适合使用的,相反在UDP中却比较适合使用。
信号驱动的工做方式以下图所示
4>I/O多路复用。
这种方式下的工做方式就比较特别了,按TCPsocket来举例,他会当listen到一个新的连接的时候将它放到一个集合中,当这个集合中的套接字有读的状况,咱们便读取,有写的状况,咱们便写,它是非阻塞I/O和信号驱动I/O再加上能够等待多个,这三个的合体,常见的函数有select,poll,epoll等,这些函数会在后面的博客中细细讲述。
它的缺点就是,不管是上面所述的哪一种函数,每次发送或者接受一个数据都会进入两次内核与用户的转换。
I/O多路复用的模型以下图
5>异步I/O
当一个异步过程调用发出后,调用者不能马上获得结果。实际处理这个调用的部件在完成后,经过状态、通知和回调来通知调用者的输入输出操做
5种I/O模型的对好比下图
能够看出最好的方式是异步I/O了固然它实现起来比较负责,阻塞I/O的可靠性最好。