彻底搞懂同步,异步,阻塞,非阻塞

12 篇文章 0 订阅

标题下面是我从几篇好评的文章中截取出来一些容易理解的部分


1、同步:是应用程序要直接参与 IO 读写的操作
对于一个socket上的输入操作,第一步就是通常涉及等待数据从网络中到达,当所等待的分组到达的时候,它就被复制到内核中的某个缓冲区中,这个时候便是我们常说的数据已经准备好了。第二步就是把数据从内核的缓冲区拷贝到应用进程的缓冲区中。这一步往往是我们进程阻塞的原因,因为用户进行需要等待去获取内核中的数据。所以socket的一次输入操作就涉及到两次的IO操作:操作系统IO和应用程序IO。
所谓的同步在这里指的是:等待数据到达或者用轮询的方式去查看数据是否到达内核缓冲区,数据到达之后,然后直到应用程序的IO操作完成后用户进程才不阻塞,也就是说同步模型中,其中真正的IO操作也就是第二步骤会将进程阻塞。

所谓的异步在这里指的是不导致应用进程阻塞的一种操作,一般工作模式就是由用户进程告知内核一个动作,然后让内核在整个操作完成后再通过指定的告知方式告知用户进程。比如用户进程在该IO操作过程中,告诉内核用户指定的缓冲区位置,以及IO操作完成之后通知程序的方式。所以在IO操作的期间,用户进程是不用管IO操作的,完全可以进行其他操作,直到内核操作完后接收结束通知就行。
2、异步:所有的 IO 读写交给操作系统去处理,应用程序只需要等待通知。
3、阻塞: 无数据准备好,系统调用比如read,recvfrom就会挂起,等到有数据准备好或者有数据了才继续执行系统调用,最后才从系统调用的函数中返回。
4、非阻塞: 这里的非阻塞是通过忙轮询去检测是否有数据准备好,没有数据准备好就立即返回,然后下面就会不断轮询,直到有数据准备好了可以开始进行数据的复制–应用程序将内核空间中的数据复制到用户空间中。

同步IO模型 :阻塞IO模型 非阻塞IO模型 信号驱动式IO

  1. 阻塞IO模型
    所有套接字默认的都是阻塞的,以recvfrom系统调用为例子,它要等到有数据报到达且被复制到应用进程的缓冲区中或者发生了错误才返回。若没有数据到达那么将一直会阻塞。

  2. 非阻塞IO模型
    进程将一个套接字设置为非阻塞就是通知内核:当前所请求的IO操作在请求的过程不需要把进程投入睡眠,而是返回一个错误。(注意这里是指请求IO操作,不是进行IO操作)

  3. 信号驱动式IO模型
    我们也可以用信号让内核在文件描述符准备就绪的时候通知用户进程,即是告知我们什么时候可以启动IO操作。就如数据准备好了,内核就会以一种形式通知用户进程将内核空间中的数据复制到用户空间中。

异步IO模型
工作机制就是:由用户进程告知内核启动一个操作,并且由内核去操作,操作完后给用户进程发一个通知,通知用户进程操作完了(包括数据从内核缓冲区拷贝到用户缓冲区的过程)。该模型与信号驱动式IO模型不同的就是,异步IO模型中,是由内核通知IO操作什么时候完成,而信号驱动式IO是由内核告知何时启动IO操作。


进程的阻塞
正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的。

文件描述符fd
文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。
文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

缓存 I/O
缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。缓存 I/O 的缺点:数据在传输过程中需要在应用程序地址空间和内核进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的。

阻塞 I/O
blocking IO。当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据在一开始还没有到达。比如,还没有收到一个完整的UDP包。这个时候kernel就要等待足够的数据到来)。这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边,整个进程会被阻塞(当然,是进程自己选择的阻塞)。当kernel一直等到数据准备好了,进行第二阶段,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。

非阻塞 I/O
nonblocking IO。linux下可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:
当用户进程发出read操作时,若kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。

I/O 多路复用
IO multiplexing就是所说的select,poll,epoll,有些地方也称这种IO方式为event driven IO。select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这些function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

异步 I/O
Linux下的asynchronous IO其实用得很少。流程如下:
用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。


非阻塞io:就是如果没有io操作还没有完成,系统直接给调用方返回错误,调用方需要不断轮询来确定是否操作完成
异步io :则是系统内核操作完成后,直接通知调用方,不需要调用方一直轮询


同步,就是我调用一个功能,该功能没有结束前,我死等结果。
异步,就是我调用一个功能,不需要知道该功能结果,该功能有结果后通知我(回调通知)。
阻塞,就是调用我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
非阻塞,就是调用我(函数),我(函数)立即返回,通过select通知调用者
同步IO和异步IO的区别就在于:数据拷贝的时候用户进程是否阻塞。等待数据准备是同步;不等待,等数据准备好通知是异步
阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否立即返回


阻塞/非阻塞:是否需要等待所需的I/O(输入输出)存在–内核空间中的数据是否已经准备好,需要等待为阻塞。
同步/异步:I/O是否完全不需要等待,不需要等待已存在的I/O从内核空间到用户空间的拷贝则为异步,需要等待为同步。
阻塞、同步本质上都是等待,同步是更深层次的等待,I/O(输入输出)存在了并不表示就能马上处理I/O数据,只有等待数据到了用户空间进程才可以进行处理操作。


论同步和异步任务的执行与回调函数
"同步模式"就是后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的.

"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。 "异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值