zoukankan      html  css  js  c++  java
  • Linux-同步异步非阻塞阻塞的解析

    一、理解同步、异步、阻塞、非阻塞

      出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
      1 老张把水壶放到火上,立等水开。(同步阻塞)
        老张觉得自己有点傻。
      2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
        老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
      3 老张把响水壶放到火上,立等水开。(异步阻塞)
        老张觉得这样傻等意义不大。
      4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
        老张觉得自己聪明了。

      所谓同步异步,只是对于水壶而言。
      普通水壶,同步;响水壶,异步。
      虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
      同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。

      所谓阻塞非阻塞,仅仅对于老张而言。
      立等的老张,阻塞;看电视的老张,非阻塞。

      情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

      再找一个买书的例子:
      异步/同步:
        异步: 你去书店,问《如何征服美少女》到货没,老板说,没到货,到货了给你打电话。你就走了,而且不需要再没接到老板电话之前再跑到书店问。
        同步:你去书店,问《如何征服美少女》到货没,老板说,没到货,你走了,过了一段时间,你又到书店,问《如何征服美少女》到货没,老板说没有,。。。。就这样,你不断的来书店自己询问。直到你鞋都跑破了.....
        注意:你离开书店(不管是异步还是同步),是可以干自己的事情的,比如去做个大保健。

      阻塞/非阻塞
        阻塞:你去书店,问《如何征服美少女》到货没有,老板说,没到货,于是你就在书店苦等,等书到货,除了干坐着,啥也干不了,直到书来。
        非阻塞:你去书店,问《如何征服美少女》到货没,老板说,没到货,你就走了。(至于还来不来书店,取决于你的心情吧。但是在计算机中,没处理完的事情,是要处理的。)

      异步/同步 是你的到消息的方式,关注的是消息通信机制 (synchronous communication/ asynchronous communication)
      阻塞/非阻塞是你怎样处理事情,关注的是程序在等待调用结果(消息,返回值)时的状态
      两组概念不是一个层面上的。

    在上面的例子中,你就相当于计算机中的 进程 ,你的两条腿就相当于CPU。(比喻很牵强也)

    二、解析
      在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作。

      在比较这两个模式之前,我们首先的搞明白几个概念,什么是阻塞和非阻塞,什么是同步和异步。

      同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知(异步的特点就是通知

      而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值


      首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作。

      同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO服用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。

      阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。

      说到阻塞,首先得说说I/O等待。I/O等待是不可避免的,那么既然有了等待,就会有阻塞,但是注意,我们说的阻塞是指当前发起I/O操作的进程被阻塞
      同步阻塞I/O便是指,当进程调用某些涉及I/O操作的系统调用或库函数时,比如accept()(注意accept也算在了i/o操作)、send()、recv()等,进程便暂停下来,等待I/O操作完成再继续运行。这是一种简单而有效的I/O模型,它可以和多进程结合起来有效的利用CPU资源,但是代价就是多进程的大量内存开销。

      同步阻塞 进程坐水,就不能烧粥
      同步非阻塞  类似于用一个进程坐水,烧粥. while(true){if... if... }  好处就是一个进程处理多个i/o请求. 劣势就是需要不停的轮询.

      区别在于等不等待数据就绪. 因为数据占了等待的80%时间. 同步非阻塞的优势就是一个进程里同时处理多个I/O操作。

      在同步阻塞I/O中,进程实际上等待的时间可能包括两部分,一个是等待数据的就绪,另一个是等待数据的复制,对于网络I/O来说,前者的时间可能要更长一些。与此不同的是,同步非阻塞I/O的调用不会等待数据的就绪,如果数据不可读或者不可写,它会立即返回告诉进程。

      比如我们使用非阻塞recv()接收网络数据的时候,如果网卡缓冲区中没有可接收的数据,函数就及时返回,告诉进程没有数据可读了。相比于阻塞I/O,这种非阻塞I/O结合反复的轮询来尝试
    数据是否就绪,防止进程被阻塞,最大的好处便在于可以在一个进程里同时处理多个I/O操作。但正是由于需要进程执行多次的轮询来查看数据是否就绪,这花费了大量的CPU时间,使得进程处于忙碌等待状态。

      非阻塞I/O一般只针对网络I/O有效,我们只要在socket的选项设置中使用O_NONBLOCK即可,这样对于该socket的send()或recv()便采用非阻塞方式。
      如果服务器想要同时接收多个TCP连接的数据,就必须轮流对每个socket调用接收数据的方法,比如recv()。不管这些socket有没有可以接收的数据,都要询问一遍,假如大部分socket并没有数据可以接收,那么进程便会浪费很多CPU时间用于检查这些socket,这显然不是我们所希望看到的。

      同步和异步,阻塞和非阻塞,有些混用,其实它们完全不是一回事,而且它们修饰的对象也不相同。
      阻塞和非阻塞是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪;


      而同步和异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞(区别就绪与读写二个阶段,同步的读写必须阻塞),异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。(等待"通知")

      多数情况下,Web服务器对这些请求采用基于队列的自由竞争,通过多执行流(多进程或多线程)来充分占 用CPU以及I/O资源,减少任何无辜的等待时间,这其中包括了很多种具体实现的并发策略,在实际应用中,特别是Web服务器,同时处理大量的文件描述符是必不可少的.多路I/O就绪通知的出现,提供了对大量文件描述符就绪检查的高性能方案,它允许进程(比如电子屏,会闻到各个饭馆做好饭菜的味道)通过一种方法来同时监视所有文件描述符,并可以快速获得所有就绪的文件描述符,然后只针对这些文件描述符进行数据访问。
      回到买面条的故事中,假如你不止买了一份面条,还在其它几个小吃店买了饺子、粥、馅饼等,因为一起逛街的朋友看到你的面条后也饿了。这些东西都需要时间来等待制作。在同步非阻塞I/O模型中,你要轮流不停的去各个小吃店询问进度,痛苦不堪。现在引入多路I/O就绪通知后,小吃城管理处给大厅安装了一块电子屏幕,以后所有小吃店的食物做好后,都会显示在屏幕上,这可真是个好消息,你只需要间隔性的看看大屏幕就可以了,也许你还可以同时逛逛附近的商店,在不远处也可以看到大屏幕。

      多路就绪:1.强调多路. 2.只针对请求数据是否就绪.不针对i/o读写
      epoll针对的是这样的场景.

      select, epoll都只需要进程(我)被动接收到数据就绪(面条)"通知".符合异步的定义. 不需要一直在饭馆等(同步阻塞).或轮询(同步非阻塞).

  • 相关阅读:
    共享纸巾更换主板代码分析 共享纸巾主板更换后的对接代码
    Python Django Ajax 传递列表数据
    Python Django migrate 报错解决办法
    Python 创建字典的多种方式
    Python 两个list合并成一个字典
    Python 正则 re.sub替换
    python Django Ajax基础
    Python Django 获取表单数据的三种方式
    python Django html 模板循环条件
    Python Django ORM 字段类型、参数、外键操作
  • 原文地址:https://www.cnblogs.com/JohnABC/p/5733985.html
Copyright © 2011-2022 走看看