I/O模型

一、基本概念
通常有同步/异步,阻塞/非阻塞四中调用方式:
1. 同步和异步主要针对客户端 
同步:所谓的同步,就是在客户端发出一个功能调用时,在没有得到结果之前,该调用不返回,也就是说必须一件一件事做,等前一件事完了之后才做后一件事。 
如:普通的B/S模式(同步):提交请求->等待服务器处理->处理完毕返回,这期间客户端浏览器不能干任何事
异步:与同步相对。当客户端一个异步过程调用发出之后,调用者不能立即得到结果,实际处理这个调用的部件在完成后,通过状态,通知和回调来通知调用者。 
如:请求通过事件触发->服务器处理(浏览器仍然可以做其他事情)->处理完毕

2. 阻塞和非阻塞主要针对服务端
阻塞 :阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态,cpu不会分配时间片,线程暂停运行)函数只有得到结果返回。 
阻塞调用和同步调用的区别:对同步来说,很多时候当前线程还是**的,只是逻辑上没有返回,如,在socket编程中调用recv函数,如果缓冲区没有数据,这个函数就会一直等待,直到有数据返回。而此前当前线程还有可能继续处理各种各样的消息。
阻塞的例子:比如去取A楼一层(假设是内核缓冲区)取快递,但是比不知道什么时候来,你有不能干别的事情,只能死等着但是可以睡觉(进程处于休眠状态),因为你知道快递把货送来时一定会给比大电话
非阻塞: 非阻塞与阻塞概念想对应,指在不能立即得到结果之前,该函数不会阻塞当前线程,而会立即返回。
非阻塞的例子:还是等快递,如果用轮询的方式,每隔5分钟去A楼一层(内核缓冲区)去看快递来了没,没来,立即返回,如果快递来了,就放到A楼一层,等你去取。

       对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞,而对于非阻塞对象,调用函数可以进入阻塞调用,对于select: 
1. 同步 我客户端(客户端调用者)一个功能,该功能没有结束前,我死等结果。 
2. 异步,我(客户端调用者)调用一个功能,不知道该功能结果,该功能有结果后通知我,即回调通知
同步和异步主要针对客户端,但是跟服务端不是完全没关系,同步和异步必须服务端配合才能实现,同步和异步由客户端控制,但是服务端是否为阻塞还是非阻塞,客户端不关心。
3. 阻塞,就是调用我(服务端被调用者,函数),我(服务端被调用者,函数)没有完全接受完数据或者没有得到结果之前,我不会返回。
4. 非阻塞,就是调用我(服务端被调用者,函数),我(服务端被调用者,函数)立即返回,通过select通知调用者

二、同步I/O和异步I/O 
       同步I/O与异步I/O的区别在与数据访问的时候进程是否阻塞 ,阻塞I/O与非阻塞I/O的区别在与:应该程序的调用是否立即返回。
       阻塞和非阻塞是指server端的进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时时直接返回还是等待就绪。
       就同步和异步是指client端访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后再读写额时候必须阻塞,异步则指主动请求数据后便可以继续处理其他任务,随后等待I/O,操作完毕的通知。

三、五种IO模型
(1)同步阻塞IO(Blocking IO)
       应用程序调用IO函数,导致应用程序阻塞,等待数据准备好。如果数据没有准备好,则程序则阻塞等待。若果数据准备好了,从内核空间拷贝到用户空间。 

I/O模型


(2)同步非阻塞IO(Non-blocking IO)
       我们把一个套接字设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样I/O操作函数将不断的测试数据是否准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断的测试中,会大量的占用CPU的时间。 

I/O模型
(3)IO多路复用(IO Multiplexing)
        I/O复用模型会用到select或者poll函数,这两个函数也会使进程阻塞,但是和阻塞I/O所不同的是,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。 

I/O模型
(4)异步IO(Asynchronous IO)
       即经典的Proactor设计模式,也称为异步非阻塞IO。调用aio_read函数,告诉内核描述字,缓冲区指针,缓冲区大小,文件偏移以及通知方式,然后立即返回。当内核将数据拷贝到缓冲区后,再通知应用程序。 

I/O模型
(5)信号驱动I/O模型 
       首先我们允许套接字接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。 

I/O模型
       同步和异步的概念描述的是用户线程与内核的交互方式:同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;而异步是指用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。
       阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回到用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。