zoukankan      html  css  js  c++  java
  • 阻塞和非阻塞,同步和异步 总结

    阻塞和非阻塞,同步和异步

    1 例子

    故事:老王烧开水。

    出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。

    老王想了想,有好几种等待方式

    1.老王用水壶煮水,并且站在那里不管水开没开,每隔一定时间看看水开了没。-同步阻塞

    老王想了想,这种方法不够聪明。

    2.老王还是用水壶煮水,不再傻傻的站在那里看水开,跑去寝室上网但是还是会每隔一段时间过来看看水开了没有,水没有开就走人。-同步非阻塞

    老王想了想,现在的方法聪明了些,但是还是不够好。

    3.老王这次使用高大上的响水壶来煮水,站在那里但是不会再每隔一段时间去看水开,而是等水开了,水壶会自动的通知他。-异步阻塞

    老王想了想,不会呀,既然水壶可以通知我,那我为什么还要傻傻的站在那里等呢,嗯,得换个方法。

    4.老王还是使用响水壶煮水,跑到客厅上网去,等着响水壶自己把水煮熟了以后通知他。-异步非阻塞

    老王豁然,这下感觉轻松了很多。


    • 同步和异步

      同步就是烧开水,需要自己去轮询(每隔一段时间去看看水开了没),异步就是水开了,然后水壶会通知你水已经开了,你可以回来处理这些开水了。
      同步和异步是相对于操作结果来说,会不会等待结果返回。

    • 阻塞和非阻塞

      阻塞就是说在煮水的过程中,你不可以去干其他的事情,非阻塞就是在同样的情况下,可以同时去干其他的事情。阻塞和非阻塞是相对于线程是否被阻塞。

    其实,这两者存在本质的区别,它们的修饰对象是不同的。阻塞和非阻塞是指进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪。
    而同步和异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞,异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。

    2 详细介绍

    网络IO的模型大致包括下面几种

    • 同步模型(synchronous IO)
      • 阻塞IO(bloking IO)
      • 非阻塞IO(non-blocking IO)
      • 多路复用IO(multiplexing IO)
      • 信号驱动式IO(signal-driven IO)
    • 异步IO(asynchronous IO)
      • 异步IO

    网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。对于一次IO访问,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间,所以一般会经历两个阶段:

    1. 等待所有数据都准备好或者一直在等待数据,有数据的时候将数据拷贝到系统内核;
    2. 将内核缓存中数据拷贝到用户进程中;

    对于socket流而言:

    1. 等待网络上的数据分组到达,然后被复制到内核的某个缓冲区;
    2. 把数据从内核缓冲区复制到应用进程缓冲区中;

    2.1 阻塞IO

    2.1.1 介绍

    这也是最常用的模型,默认情况下所有的套接字都是 阻塞 的;

    我们把recvfrom函数视为系统调用,因为我们正区分进程和内核,系统调用一般都会从在应用进程空间中运行切换到内核空间中运行,一段时间后又再切换回来;

    我们可以从图中看到,应用进程从 进行系统调用复制数据报到应用进程的缓冲区完成 的整段时间内是被阻塞的;在这个过程中,要么正确到达,要么系统调用被信号打断;直到数据报被复制到用户进程完成后,用户进程才解除阻塞的状态,当然,这是用户进程自己进行的阻塞;

    2.1.2 优点和缺点

    • 优点:能够及时返回数据,无延迟;方便调试;
    • 缺点:需要付出等待的代价;

    2.2 非阻塞IO

    2.2.1 介绍

    非阻塞,当所请求的I/O操作非得把当前进程设置成睡眠才能完成时,不要把当前进程设置成睡眠,而是返回一个错误信息(数据报没有准备好的情况下),此时当前进程可以做其它的事情,不用阻塞;

    从图中可以得知,前三次系统调用时都没有数据可以返回,内核均返回一个 EWOULDBLOCK,并且不会阻塞当前进程,直到第四次询问内核缓冲区是否有数据的时候,此时内核缓冲区中已经有一个准备好的数据,因此将内核数据复制到用户空间,此时系统调用则返回成功;

    当一个应用进程像这样对一个非阻塞socket循环调用 recv/recvfrom 时,则称为轮询;应用进程持续轮询内核,以查看某个操作是否就绪,这么做往往消耗大量的CPU时间。

    2.2.2 优点和缺点

    • 优点:相较于阻塞模型,非阻塞不用再等待任务,而是把时间花费到其它任务上,也就是这个当前线程同时处理多个任务;

    • 缺点:导致任务完成的响应延迟增大了,因为每隔一段时间才去执行询问的动作,但是任务可能在两个询问动作的时间间隔内完成,这会导致整体数据吞吐量的降低。

    2.3 IO多路复用

    2.3.1 介绍

    有了I/O复用,我们就可以调用 select或poll,让其阻塞在两个系统调用(1.询问数据是否准备好并且直到数据准备好才返回;2.内核是否把数据全部复制完成到用户进程)中的某一个之上

    图中阻塞于 select 调用,等待数据报套接字变为可读。当select返回套接字可读这一条件的时候,则调用 recvfrom 把所读数据报复制到应用进程缓冲区;

    之前的同步非阻塞方式需要用户进程不停的轮询,但是IO多路复用不需要不停的轮询,而是派别人去帮忙循环查询多个任务的完成状态,UNIX/Linux 下的 select、poll、epoll 就是干这个的;select调用是内核级别的,select轮询相对非阻塞的轮询的区别在于---前者可以等待多个socket,能实现同时对多个IO端口进行监听,当其中任何一个socket的数据准好了,就能返回进行可读,然后进程再进行recvform系统调用,将数据由内核拷贝到用户进程,当然这个过程是阻塞的。select或poll调用之后,会阻塞进程,与blocking IO阻塞不同在于,此时的select不是等到socket数据全部到达再处理, 而是有了一部分数据(网络上的数据是分组到达的)就会调用用户进程来处理。如何知道有一部分数据到达了呢?监视的事情交给了内核,内核负责数据到达的处理。

    我认为上面那句话中存在两个重要点:1.对多个socket进行监听,只要任何一个socket数据准备好就返回可读;2.不等一个socket数据全部到达再处理,而是一部分socket的数据到达了就通知用户进程;

    其实 select、poll、epoll 的原理就是不断的遍历所负责的所有的socket完成状态,当某个socket有数据到达了,就返回可读并通知用户进程来处理;

    2.3.2 优点和缺点

    • 优点:能够同时处理多个连接,系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源。
    • 缺点:如果处理的连结数目不高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。(因为阻塞可以保证没有延迟,但是多路复用是处理先存在的数据,所以数据的顺序则不管,导致处理一个完整的任务的时间上有延迟)

    2.3.3 同步非阻塞和多线程+同步阻塞

    高并发的程序一般使用同步非阻塞方式而非多线程 + 同步阻塞方式。要理解这一点,首先要扯到并发和并行的区别。比如去某部门办事需要依次去几个窗口,办事大厅里的人数就是并发数,而窗口个数就是并行度。也就是说并发数是指同时进行的任务数(如同时服务的 HTTP 请求),而并行数是可以同时工作的物理资源数量(如 CPU 核数)。通过合理调度任务的不同阶段,并发数可以远远大于并行度,这就是区区几个 CPU 可以支持上万个用户并发请求的奥秘。在这种高并发的情况下,为每个任务(用户请求)创建一个进程或线程的开销非常大。而同步非阻塞方式可以把多个 IO 请求丢到后台去,这就可以在一个进程里服务大量的并发 IO 请求。

    2.4 信号驱动式I/O模型

    首先开启套接字的信号驱动式IO功能,并且通过 sigaction 系统调用安装一个信号处理函数,该函数调用将立即返回,当前进程没有被阻塞,继续工作;当数据报准备好的时候,内核则为该进程产生 SIGIO 的信号,随后既可以在信号处理函数中调用 recvfrom 读取数据报,并且通知主循环数据已经准备好等待处理,也可以通知主循环让它读取数据报;(其实就是一个待读取的通知和待处理的通知);

    2.5 异步式I/O模型

    我们调用 aio_read 函数,给内核传递描述符、缓冲区指针、缓冲区大小和文件偏移,并且告诉内核当整个操作完成时如何通知我们。该函数调用后立即返回,不被阻塞;

    2.6 比较

    推荐文章
    IO多路复用机制详解
    I/O模型与多路复用
    聊聊Linux 五种IO模型
    聊聊IO多路复用之select、poll、epoll详解

  • 相关阅读:
    QFramework 使用指南 2020(二):下载与版本介绍
    QFramework 使用指南 2020 (一): 概述
    Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践
    Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介
    Unity 游戏框架搭建 2017 (二十三) 重构小工具 Platform
    Unity 游戏框架搭建 2017 (二十二) 简易引用计数器
    Unity 游戏框架搭建 2017 (二十一) 使用对象池时的一些细节
    你确定你会写 Dockerfile 吗?
    小白学 Python 爬虫(8):网页基础
    老司机大型车祸现场
  • 原文地址:https://www.cnblogs.com/George1994/p/6702084.html
Copyright © 2011-2022 走看看