对同步和异步、阻塞和非阻塞的总结

最近被问到对同步和异步的理解,当时感觉一下子不知道如何顺畅的表达,回来整理一下思路。
我自己的理解如下:

同步和异步是针对一次任务的执行而言的。
同步:发起任务后,任务的发起者不能执行其他任务,直到得知任务结果(成功/失败)。也就是说发起者只有在前一个任务完成后才会执行下一个任务,因此发起者的任务是串行执行的。
异步:发起任务后,任务的发起者即可执行下一个任务,即使还未确认任务是否完成,发起者可以通过某些方式(如查询状态,回调通知等)来得知之前的任务是否完成,但得到前一个任务的结果之前,后面的任务可能已经在执行了。
以消息发送任务举例:
如果是同步操作,消息发送者启动消息发送后,不会继续后面的任务,而是阻塞或轮询发送的结果,当确认接收方已经收到数据后,发送方才会继续后面的任务。而如果是异步操作,消息发送者启动消息发送后就会继续后面的任务,此时前一个消息发送任务的结果是未知的。
同步/异步并不是针对某个接口的调用来说的,一个接口内部的执行过程可能又分成多个任务,这些任务有些可能是同步的,有些又可能是异步的。
例如Socket的发送调用的write API,内部可分为三部分,一是将用户空间的数据拷贝到内核态,二是内核再把数据DMA到网卡,三是网卡将数据发送到对端并获得ACK(TCP方式)。发送任务的成功与否,从任务整体上应该看是否已写入接收端内存。而这三部分工作中第一部分是同步的,后面则是异步的,对于发送任务的执行者来说,write接口调用返回成功,可以确保数据已经提交到内核,而接口返回时DMA操作以及网卡数据发送并不能确保成功,更无法确认数据已经发送到对端。

阻塞和非阻塞是针对一次接口调用而言的。
阻塞:接口调用可能导致进程阻塞,即可能导致上下文切换。
非阻塞:接口调用立即返回不会导致进程阻塞。
阻塞接口执行的可能是同步任务,例如malloc,接口返回必然可以知道内存分配的结果(成功/失败);也可能“包含”异步任务。例如前面说到的write接口,网卡发送数据这部分任务是异步的,接口返回并不代表对端已经收到数据,即并不能确认任务成功失败。
非阻塞接口执行的也可能是同步任务。例如NONBLOCK socket的accept,无论是否有连接过来,该接口都会立即返回(没有连接返回EAGAIN),不会使得调用者阻塞,但accept这一任务的结果在接口返回时就是明确的:要么有连接过来(得到连接的fd),要么没有或失败(得到相应的错误码)。

MPI关于阻塞和非阻塞接口的定义也体现与同步异步的区别(https://computing.llnl.gov/tutorials/mpi/#Getting_Started)

  • Blocking:
    • A blocking send routine will only "return" after it is safe to modify the application buffer (your send data) for reuse. Safe means that modifications will not affect the data intended for the receive task. Safe does not imply that the data was actually received - it may very well be sitting in a system buffer.
    • A blocking send can be synchronous which means there is handshaking occurring with the receive task to confirm a safe send.
    • A blocking send can be asynchronous if a system buffer is used to hold the data for eventual delivery to the receive.
    • A blocking receive only "returns" after the data has arrived and is ready for use by the program.
posted @ 2017-07-08 17:02  NumberSix  阅读(1444)  评论(0编辑  收藏  举报