• [原创] 同步、异步、阻塞、非阻塞详解


    为了阐释方便,需要先引入一个概念:

    比进程小的可以是线程,比线程还小的是什么呢?--协程

        协程在线程中一个不带返回值的函数调用叫做协程。(我们暂且这样定义)

    比如一个线程执行了以下流程:
         做饭-吃饭
    那么做饭的过程就叫协程,吃饭的过程也叫协程。

        →同步、异步在阐述场景的时候总是容易和阻塞与非阻塞混淆,其实他们是不同维度的概念。

    (1)同步、异步: 描述的是协程之间的关系;
    (2)阻塞、非阻塞:描述的是一个协程的属性;

    这里的"协程"不能换成"线程",因为单"线程"也可以通过某种办法维护很多并行的协程,比如IO复用。
    这里的"协程"也不能换成"事件",因为"事件"不是用于描述过程的;
    这里的"协程"也不能换成"函数",因为"函数"是代码中的概念;
    这里的"协程"也不能换成"任务",因为"任务"有可能是一个流水线,甚至可能要多个线程完成。

    1、阻塞:协程执行过程中会让线程挂起;

    比如:A在焖米饭,没看焖好就一直等在电饭锅边,什么也不干;

    2、非阻塞:协程在执行过程中没有完成也返回;

    比如:A在焖米饭,看见没焖好米饭,也去干别的事了;
    但是A需要隔一会就看一下米饭是否熟了。
    所以在非阻塞的实现过程中,为了保证得到结果,有时需要设计轮询的方式来实现。
    比如:《Unix环境网络编程》中,第六章说的recvfrom

    3、同步:一件事完成之后才能做另一件事,与线程和进程数基本无关,因为它描述的是协程之间的关系。

    比如:做好饭后才能吃饭。也可以细分成多种情况:
    A做好饭后,A才能吃饭;(一般的函数都是这个范畴:如read/write)
    A做好饭后,B才能吃饭;(锁、互斥量就是解决这个问题的)
    A做好饭后,ABCDEF...才能吃饭;(条件变量就是解决这个问题的)

    4、异步:与同步相反,做事并不依赖于其他事产生的结果。

    比如:A做好饭了我就吃,没做好饭我也不会张着嘴在饭桌前干等着,该干什么干什么。
    Linux中通常说的AIO,epoll(),libevent等都是异步的主要应用。异步通常和“事件”联系在一起,一般是先把描述符绑定到事件上,当事件发生后,触发注册的回调函数。

    异步实现有两种方式:
    (1)信号:A做好饭之后,敲个钟;
    (2)回调函数:饭做好了之后,挨个叫吃饭。

    综上,可以得到以下结论:

    阻塞是实现同步的一种手段。(锁、互斥量、条件变量等的实现都是要让线程挂起)
    轮询时保证非阻塞函数能够得到肯定结果的一种手段。(另外一种方式就是需要用异步的方式触发了)
    异步可以是保证非阻塞函数得到肯定结果的一种手段。

     

    如果看着有些糊涂,那么我们用Linux的IO来介绍一下阻塞、非阻塞、同步、异步这些概念:

    基本的Linux IO矩阵

    (1)同步阻塞:

    如read/write,在结果返回之前,当前线程会被挂起,函数只有在得到结果之后才会返回。recvfrom举例如下:

    (2)同步非阻塞:

    如read/write的fd指定O_NONBLOCK,在不能立刻得到结果之前,函数不会阻塞当前线程,而会立刻返回。
    当前线程也可以执行其他的操作,但得到的返回值是不一样的,如果返回值比较重要,就需要轮询,比如recvfrom函数
    虽然不会阻塞进程,但需要不断轮询来查询结果:

    (3)异步阻塞:

    如IO复用中的select, 同时维护着多个文件描述符,只要有一个描述符返回时,返回值就大于0。
    当然,select函数实现了单线程的异步,其实如果每个线程都维护一个任务,任务之前通过锁来保证执行顺序,这才是通常意义上的异步阻塞。recvfrom举例如下:

    (4)异步非阻塞:

    如AIO,linux中的epoll,先把函数注册给相应的事件,当满足条件之后,触发相应的操作。recvfrom举例如下:

    如有谬误,请多指教,本文参考以下大神博客:

    http://blog.csdn.net/heyutao007/article/details/7065166
    http://blog.chinaunix.net/uid-26000296-id-3754543.html
    http://blog.chinaunix.net/uid-26000296-id-3754118.html

  • 相关阅读:
    AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式
    java如何得到GET和POST请求URL和参数列表
    Tomcat处理HTTP请求源码分析(下)
    Tomcat处理HTTP请求源码分析(上)(转)
    tomcat免重启随意更改java代码 提高开发效率
    ServletRequest中getReader()和getInputStream()只能调用一次的解决办法
    Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
    Tomcat处理HTTP请求源码分析(上)
    Drupal views中实现两列布局
    (转) 转换Drupal7模块到Drupal8
  • 原文地址:https://www.cnblogs.com/bugutian/p/5207909.html
Copyright © 2020-2023  润新知