IO模型之一:Unix的五种I/O模型

1 阻塞I/O(blocking IO)

  应用程序调用一个IO函数,导致应用程序阻塞,如果数据已经准备好,从内核拷贝到用户空间,否则一直等待下去。一个典型的读操作流程大致如下图,当用户进程调用recvfrom这个系统调用时,kernel就开始了IO的第一个阶段:准备数据,就是数据被拷贝到内核缓冲区中的一个过程(很多网络IO数据不会那么快到达,如没收一个完整的UDP包),等数据到操作系统内核缓冲区了,就到了第二阶段:将数据从内核缓冲区拷贝到用户内存,然后kernel返回结果,用户进程才会解除block状态,重新运行起来。blocking IO的特点就是在IO执行的两个阶段用户进程都会block住;

                                                   

 2 非阻塞I/O(nonblocking IO)

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

        当用户进程发出read操作时,如果kernel中数据还没准备好,那么并不会block用户进程,而是立即返回error,用户进程判断结果是error,就知道数据还没准备好,用户可以再次发read,直到kernel中数据准备好,并且用户再一次发read操作,产生system call,那么kernel 马上将数据拷贝到用户内存,然后返回;所以nonblocking IO的特点是用户进程需要不断的主动询问kernel数据好了没有。

  阻塞IO一个线程只能处理一个IO流事件,要想同时处理多个IO流事件要么多线程要么多进程,这样做效率显然不会高,而非阻塞IO可以一个线程处理多个流事件,只要不停地询所有流事件即可,当然这个方式也不好,当大多数流没数据时,也是会大量浪费CPU资源;为了避免CPU空转,引进代理(select和poll,两种方式相差不大),代理可以观察多个流I/O事件,空闲时会把当前线程阻塞掉,当有一个或多个I/O事件时,就从阻塞态醒过来,把所有IO流都轮询一遍,于是没有IO事件我们的程序就阻塞在select方法处,即便这样依然存在问题,我们从select出只是知道有IO事件发生,却不知道是哪几个流,还是只能轮询所有流,epoll这样的代理就可以把哪个流发生怎样的IO事件通知我们; 

                                           

 3 非阻塞I/O(nonblocking IO)

  

猜你喜欢

转载自www.cnblogs.com/sharing-java/p/10791802.html