zoukankan      html  css  js  c++  java
  • 关于Blocking IO, NonBlocking IO 和 Asynchronous I/O的理解

    概括来说,一个IO操作可以分为两个部分:发出请求、结果完成。如果从发出请求到结果返回,一直Block,那就是Blocking IO;如果发出请求就可以返回(结果完成不考虑),就是non-blocking IO;如果发出请求就返回,结果返回是Block在select或者poll上的,则其只能称为IO multiplexing;如果发出请求就返回,结果返回通过Call Back的方式被处理,就是AIO。

    文[2]中图画的不错,说的也比较清楚借来用一下。

    Blocking IO

    这个最好理解了,在Blocking IO模式下,函数调用只有在操作完成后才会返回。下图是它调用过程的图示:

     

    重点解释下上图,下面例子都会讲到。首先application调用 recvfrom()转入kernel,注意kernel有2个过程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此过程一直是阻塞的。

    Non-Blocking IO

    Non-Blocking 是Blocking的反,也就是说,即使操作没有完成,函数也可以返回。调用过程如下:

     

    可以看见,如果直接操作它,那就是个轮询。。直到内核缓冲区有数据

    AIO也是这样啊?对!这是Non-Blocking IO 和AIO的共同点。其实从概念层面来说Non-Blocking IO 就是AIO,他们没有什么区别。但是Non-Blocking IO是对文件描述符(*nix)或者Handle(Windows)的设置,在执行操作时不需要特殊的数据结构。Non-Blocking IO提交请求后只能通过提交的操作函数来查询操作是否完成,这是一个很大的限制。而AIO往往会提供多种通知或者查询机制,也就是说用Non-Blocking IO时只能轮询,而AIO有更多选择。所以是否支持轮询外的其他机制是AIO和Non-Blocking IO的区别。

    Non-Blocking IO和Blocking IO的区别仅仅在操作是否能够立刻完成,如果能够立刻完成,IO函数的行为是一样的;如果不能立刻完成,Non-Blocking IO会返回EAGAIN或者EWOULDBLOCK,而Blocking IO会一直阻塞。

    I/O multiplexing (select and poll)
    最常见的I/O复用模型,select。

     

    select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,但是select能处理多个套接字。

    signal driven I/O (SIGIO)
    只有UNIX系统支持,感兴趣的课查阅相关资料

     

    I/O multiplexing (select and poll)相比,它的优势是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。

    Asynchronous I/O (the POSIX aio_functions)

    很少有*nix系统支持,windows的IOCP则是此模型。

    The POSIX asynchronous I/O (AIO) interface allows applications to initiate one or more I/O operations that are performed asynchronously (i.e., in the background). The application can elect to be notified of completion of the I/O operation in a variety of ways: by delivery of a signal, by instantiation of a thread, or no notification at all.

    AIO让应用发起一个操作请求,让这个请求被异步地执行。应用可以选择在操作完成时被通知到或者不被通知。所以通知机制并不是AIO的核心,但是需要提供几种选择。在Windows上,Overlapped IO是AIO的实现,IOCP在Overlapped IO的基础上提供了高效的通知机制。

     

    完全异步的I/O复用机制,因为纵观上面其它四种模型,至少都会在由kernel copy data to application时阻塞。而该模型是当copy完成后才通知application,可见是纯异步的。好像只有windows的完成端口是这个模型,效率也很出色。

    下面是以上五种模型的比较


     

    可以看出,越往后,阻塞越少,理论上效率也是最优。

    下面可以把select,epoll,iocp,kqueue按号入座。

    select和iocp分别对应第3种与第5种模型,那么epoll与kqueue呢?其实也于select属于同一种模型,只是更高级一些,可以看作有了第4种模型的某些特性,如callback机制。

    那么,为什么epoll,kqueue比select高级? 

    答案是,他们无轮询。因为他们用callback取代了。想想看,当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。

    windows or *nix (IOCP or kqueue/epoll)?

    诚然,Windows的IOCP非常出色,目前很少有支持asynchronous I/O的系统,但是由于其系统本身的局限性,大型服务器还是在UNIX下。而且正如上面所述,kqueue/epoll 与 IOCP相比,就是多了一层从内核copy数据到应用层的阻塞,从而不能算作asynchronous I/O类。但是,这层小小的阻塞无足轻重,kqueue与epoll已经做得很优秀了。

    提供一致的接口,IO Design Patterns

    实际上,不管是哪种模型,都可以抽象一层出来,提供一致的接口,广为人知的有ACE,Libevent这些,他们都是跨平台的,而且他们自动选择最优的I/O复用机制,用户只需调用接口即可。说到这里又得说说2个设计模式,Reactor and Proactor。有一篇经典文章http://www.artima.com/articles/io_design_patterns.html值得阅读,Libevent是Reactor模型,ACE提供Proactor模型。实际都是对各种I/O复用机制的封装。

    Java nio包是什么I/O机制?

    我曾天真的认为java nio封装的是IOCP。。现在可以确定,目前的java本质是select()模型,可以检查/jre/bin/nio.dll得知。至于java服务器为什么效率还不错。。我也不得而知,可能是设计得比较好吧。。-_-。

    =====================分割线==================================

    总结一些重点:

    只有IOCP是asynchronous I/O,其他机制或多或少都会有一点阻塞。 select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善 epoll, kqueue是Reacor模式,IOCP是Proactor模式。 java nio包是select模型。。

    Reference:

    1. http://www.artima.com/articles/io_design_patterns.html

    2. http://hi.baidu.com/ailuoli/blog/item/f9fe370f0dee7bf1ab6457e7.html

  • 相关阅读:
    Hanoi塔
    采药
    进制转换(大数)
    Load Balancing with NGINX 负载均衡算法
    upstream模块实现反向代理的功能
    epoll
    在nginx启动后,如果我们要操作nginx,要怎么做呢 别增加无谓的上下文切换 异步非阻塞的方式来处理请求 worker的个数为cpu的核数 红黑树
    粘性会话 session affinity sticky session requests from the same client to be passed to the same server in a group of servers
    负载均衡 4层协议 7层协议
    A Secure Cookie Protocol 安全cookie协议 配置服务器Cookie
  • 原文地址:https://www.cnblogs.com/whyandinside/p/2379234.html
Copyright © 2011-2022 走看看