天天看点

程序员成长之旅——同步IO和异步IO(五种IO模型)

程序员成长之旅——同步IO和异步IO(五种IO模型)

    • 同步和异步
        • 同步
        • 异步
    • 消息通知
    • 场景比喻
    • 阻塞和非阻塞
        • 阻塞
        • 非阻塞
    • 事例
    • 同步IO
        • 阻塞IO
        • 非阻塞IO
        • 信号驱动IO
        • 多路转接IO
    • 异步IO
    • 五种IO模型比对
    • 钓鱼解析其五种IO模型

在这里首先要知道一点就是IO操作其实总的就分为两种,第一种是等待的时间,第二种就是数据的拷贝,而往往等待的时间都是高于数据拷贝的,因此为了IO的更加高效,我们都是通过来缩短等待的时间来提生IO的效率的。其次在学习五种IO模型的前提下,先了解一下其概念。同步,异步,阻塞和非阻塞。

同步和异步

这两个概念与消息的通知机制有关。

同步

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。比如,调用readfrom系统调用时,必须等待IO操作完成后才能返回。它是一个可靠的任务序列。

异步

异步的概念和其同步的概念是与之对应的,当一个异步过程调用发出后,调用者不能立即得到结果。实际处理这个调用的部件在完成后,通过状态、通知、和回调来告诉调用者。实际处理的是否完成此任务,它是不得而知的,因此它是一个不可靠的任务序列。

消息通知

上面已知异步的概念和同步的概念是与之相对的。当一个同步的调用发出后,调用者要一直等待返回消息结果通知后,才能进行后续的执行;而当一个异步过程调用的时候,调用者不能立即得到返回消息。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者的。

这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。使用那一种通知机制,依赖于执行部件的实现,除非执行部件提供多种选择,否则是不受调用者控制的。

1.如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低;

2.如果使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数和通知几乎一样。

场景比喻

举个例子,比如我去海底捞去吃饭,可能就有两种方式:

1.选择排队等候;

2.另外选择一个号码,等到我的号码的时候,广播通知我去就餐;

第一种:前者(排队等候)就相当于同步等待消息的通知,也就是我要一直等待前面客人用餐完。

第二种:后者(等待广播通知)就是异步等待消息通知。在异步消息处理中,等待消息通知者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码,喊号)找到等待该事件的人。

阻塞和非阻塞

阻塞和非阻塞与等待消息通知时的状态有关。

阻塞

阻塞调用是指调用返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。

阻塞和同步是两种不同的概念。首先同步是对于消息的通知机制而言,阻塞是针对等待时的状态来说的。而且对于同步调用来说,很多时候当前线程还是激活的,只是逻辑上当前没有返回而已。

非阻塞

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回,并设置相应的errno。

虽然表面上看非阻塞的方式可以明显的提高CPU的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的CPU执行时间能不能补偿系统的切换成本需要好好评估。

事例

以小王下载文件为例,对上述概念做以理解:

1.同步阻塞:小王一直盯着下载进度条,到100%的时候就完成。

同步:等待下载完成通知;

阻塞:等待下载完成通知过程中,不能做其它任务处理;

2.同步非阻塞:小王提交下载任务后就去干别的,每过一段时间就去瞄一眼进度条,看是否完成。

同步:等待下载完成通知;

非阻塞:等待下载完成通知过程中,去看动漫去了,只是时不时会瞄一眼进度条;【小王必须在两个任务操作中来回切换,关注下载进度】

3.异步阻塞:小王打开了下载完成后的提示音,下载完成会通知他,不过在这期间,他一直会等待这个声音。

异步:下载完成后的提示音;

阻塞:等待提示音的过程中,不能做其它任务处理;

4.异步非阻塞小王打开了下载完成后的提示音,下载完成会通知他,不过在这期间,他可以去干其它事情。

异步:下载完成后的提示音;

非阻塞:等待提示音的过程中,去干其它事情了,只需要接收提示音的通知;

同步IO

阻塞IO

同步阻塞IO模型是最常用、最简单的模型。在Linux下,默认情况下,所有套接字都是阻塞的。下面以阻塞套接字的recvfrom的调用图来说明阻塞:

程序员成长之旅——同步IO和异步IO(五种IO模型)

从上面可看出,一个应用进程调用一个recvfrom请求,但是它不能立即收到回复,知道数据返回,然后将数据从内核空间拷贝到用户空间。

第一二阶段皆是阻塞。

优缺点:优点是简单,实时性高,响应及时无延迟,但缺点也很明显,需要阻塞等待,性能差;

非阻塞IO

与阻塞式I/O不同的是,非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error(EAGAIN 或 EWOULDBLOCK)。进程在返回之后,可以处理其他的业务逻辑,过会儿再发起recvform系统调用。采用轮询的方式检查内核数据,直到数据准备好。再拷贝数据到进程,进行数据处理。

在linux下,可以通过设置socket套接字选项使其变为非阻塞。下图是非阻塞的套接字的recvfrom操作

程序员成长之旅——同步IO和异步IO(五种IO模型)

如上图,前三次调用recvfrom请求,但是并没有数据返回,所以内核返回errno(EWOULDBLOCK),并不会阻塞进程。但是当第四次调用recvfrom,数据已经准备好了,然后将它从内核空间拷贝到程序空间,处理数据。

在非阻塞状态下,IO执行的等待阶段并不是完全的阻塞的,但是第二个阶段依然处于一个阻塞状态。

优缺点:

优点:能在等待任务完成的时间里干其他的事情(也就是后台多个任务可以同时执行)。

缺点:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。这会导致整体数据的吞吐量降低。

信号驱动IO

允许socket进行信号驱动IO,并注册一个信号处理函数,进程继续运行并不阻塞。当数据准备好的时候,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

程序员成长之旅——同步IO和异步IO(五种IO模型)

阻塞在IO操作的第二个阶段

多路转接IO

IO 多路复用的好处就在于单个进程就可以同时处理多个网络连接的IO。它的基本原理就是不再由应用程序自己监视连接,取而代之由内核替应用程序监视文件描述符。

程序员成长之旅——同步IO和异步IO(五种IO模型)

优势

  与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降底了系统的维护工作量,节省了系统资源。

主要应用场景:

  ①、服务器需要同时处理多个处于监听状态或者多个连接状态的套接字;

  ②、服务器需要同时处理多种网络协议的套接字,如同时处理TCP和UDP请求;

  ③、服务器需要监听多个端口或处理多种服务;

  ④、服务器需要同时处理用户输入和网络连接。

异步IO

上述四种IO模型都是同步的。相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,就可以去处理其他的逻辑了,无论内核数据是否准备好,都会直接返回给用户进程,不会对进程造成阻塞。等到数据准备好了,内核直接复制数据到进程空间,然后从内核向进程发送通知,此时数据已经在用户空间了,可以对数据进行处理了。

程序员成长之旅——同步IO和异步IO(五种IO模型)

IO两个阶段,进程都是非阻塞的。

五种IO模型比对

程序员成长之旅——同步IO和异步IO(五种IO模型)

其实前四种I/O模型都是同步I/O操作,他们的区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用。相反,异步I/O模型在这等待数据和接收数据的这两个阶段里面都是非阻塞的,可以处理其他的逻辑用户进程将整个IO操作交由内核完成,内核完成后会发送通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。

钓鱼解析其五种IO模型

阻塞IO

张三去钓鱼的时候,他只有一个鱼钩,当他将鱼钩放上鱼饵放入水里的那一刻起,他就一直在等待,只专注与这一件事情,直到有鱼咬住鱼饵,他拉起来,表示这个过程完成。

非阻塞IO

李四去钓鱼的时候,同样是只有一个鱼钩,当他放入水里的那一刻之后,没有鱼儿上钩的话,他会拉起来鱼钩,然后修整一下,可以干一下其他事情,之后一直重复这个动作,直到鱼儿上钩,表示这个过程完成。

信号驱动IO

王五去钓鱼的时候,同样是一个鱼钩,但不同的是他钓鱼的同时,将鱼钩上绑了一个铃铛,在此期间,他还可以和李四交流,一旦铃铛响了,他拉上来之后代表完成。

多路转接IO

马六他有多个鱼竿,假设他可以忙的过来,只要有一个鱼竿有响应,他就可以拉起来了,这个概率就相对比比较大了。

异步IO

田七去钓鱼的时候,刚拿起装备,这时候有急事呼叫他,但与此同时他还想吃钓到的鱼,这时候,他就可以雇人帮他钓鱼,等钓好之后打电话通知他,将其装备鱼给他,就代表这个过程完成了。

参考网址

以上有任何问题的,欢迎大佬们指正

继续阅读