浅谈I/O模型里的同步、异步、阻塞、非阻塞

Linux的网络IO模型

  Linux有五种网络IO模型,分别是阻塞IO,非阻塞IO,IO多路复用、异步IO、信号驱动IO。
  可能由于中华文字的博大精深,同步和阻塞,异步和非阻塞这几个相近的概念许多人无法很好的理解。在本篇文章,我会分别从五种IO模型的工作流程入手,讲讲IO模型中的阻塞、非阻塞、异步以及异步的反面同步分别代表什么含义。
  文章中阐述的是个人理解,若有不同见解,希望能留下宝贵的评论,不胜感激!

程序中网络数据的接收过程

  在说阻塞这些概念之前,我们得先了解应用程序接收网络数据的一个粗略流程。

步骤1
步骤2
步骤3
步骤4
步骤5
数据到达网卡
DMA将数据拷到内存
触发硬中断,通知CPU数据拷贝完成
CPU处理数据,并将处理后的数据送到Socket缓冲队列
数据从缓冲区拷到用户区
接收到数据

  从上图,不难看出,一个网络IO请求的完成,可以分为两个大阶段。其中步骤1到步骤3我称为数据的准备阶段,步骤4到步骤5我称为数据的拷贝阶段

阻塞IO和非阻塞IO

阻塞IO


  上图是Unix网络编程中,阻塞IO的流程图。图中可以看到,当调用recv函数接收数据后,需要等待数据到来,同时还要等待数据从内核拷贝到用户进程。
  在阻塞IO中,我们被阻塞在了两个阶段:
  ①第一个阶段是图中的wait for data阶段,也就是准备阶段
  ②第二个阶段是图中的copy data from kernel to user阶段,也就是拷贝阶段

非阻塞IO

在这里插入图片描述
  上图是Unix网络编程中,非阻塞IO的流程图。图中可以看到,当调用recv函数接收数据后,若此时数据还未准备好,那么立马给调用者返回一个错误,同时用户需要再次调用recv反复询问内核数据是否准备好,
  等到数据准备好后,且用户再次调用了recv,这时数据从内核拷贝到用户进程。
  在非阻塞IO中,我们被阻塞在了一个阶段:
  ①阻塞的阶段位于图中的copy data from kernel to user阶段,也就是拷贝阶段

阻塞和非阻塞的区别

  从上面,我们可以总结出两点:
  ①阻塞IO会阻塞在准备阶段拷贝阶段两个阶段中
  ②非阻塞IO不会阻塞在准备阶段,此时,在数据准备好之前你都是自由的,等到数据准备好后,会被阻塞在拷贝阶段
  因此阻塞和非阻塞区别于在数据流的准备阶段,程序是否会被阻塞。

信号驱动IO

在这里插入图片描述
  上图是Unix网络编程中,信号驱动IO的流程图。图中可以看到,当发起信号驱动IO的时候,首先会向内核注册一个信号处理的函数,此时程序不会被阻塞。接着直到准备阶段的数据准备完毕后,内核会发送一个SIGIO信号,同时触发信号处理函数,告知用户此时数据已经准备完毕
  用户知道数据已经准备完毕后,可以调用recv函数,此时程序会被阻塞住,直至缓冲队列数据拷贝到用户进程。
  从图中,不难总结出信号驱动IO模型的特点:
  ①信号驱动IO不会阻塞在准备阶段
  ②信号驱动IO会被阻塞在拷贝阶段

IO多路复用

  多路复用,在通讯里,是一种能实现在一个信道上传输多路信号的技术。
  IO多路复用和通讯的多路复用不能说有点类似,在我看来,除了一个多字以外,其它貌似都不沾边。
  IO多路复用是为了检查多个IO流的变化而诞生的。最经典的实现就是select,poll以及epoll。
在这里插入图片描述
  上图是Unix网络编程中,IO多路复用的流程图。图中可以看到,在调用select后,程序会一直阻塞等待,直到监控的Socket里至少有一个Socket的数据准备就绪了,此时会返回。接着,用户再调用recv函数,等待数据从内核拷贝到用户进程。
  从图中不难看出,IO多路复用和阻塞IO有异曲同工之妙,那就是都会阻塞在准备阶段拷贝阶段,不仅如此,中间还多了2个步骤,一个内核返回和一个系统调用。
  如此看来,IO多路复用性能岂不是更差了?那不尽然!IO多路复用妙在能同时阻塞多个socket,当其中至少有一个socket的数据准备就绪时便可返回,此时能保证至少接收到1个socket的数据。而不是每次轮询所有socket,得到的结果却都是数据未就绪。

异步IO

  五种IO模型中,有个异步模型。在Unix网络编程中,异步模型的工作流程图如下:
在这里插入图片描述
  图中可以看到,当发起异步IO的时候,会立刻返回,此时用户不会被阻塞。等到数据准备结束,且数据成功拷贝到用户进程时,内核通过发送一个信号,通知用户IO完成。
  从图中,不难总结出异步IO模型的特点:
  ①异步IO不会阻塞在准备阶段
  ②异步IO不会阻塞在拷贝阶段

什么是同步IO

  从异步IO模型我们得知,一个异步IO从发起到拿到数据,这个过程程序并未阻塞。
  从上反推,如果一个IO请求,从发起到拿到数据这个过程,会阻塞住程序,那么它就是一个同步IO。
  不难看出,阻塞IO、非阻塞IO、IO多路复用、信号驱动IO都属于同步IO。它们在准备阶段拷贝阶段中,程序至少都会被阻塞在其中一个阶段。

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

  总算到了收篇的时候了。刚才,我们已经知道了何为同步IO,何为异步IO。这边再总结下,如果调用者主动发起IO请求后,该IO请求会阻塞应用程序,那么这个IO它就是同步,反之就是异步的。
  阻塞和非阻塞的区别在上面已经说明了。阻塞和非阻塞只是阐述同步IO里头,数据准备阶段这一环节的状态:是一直等待数据准备结束,还是轮询直至数据准备结束。
  至于网上说的同步阻塞,同步非阻塞,在我看来并不是从网络IO模型切入,可能更侧重于多线程的角度。因为在网络IO模型中,同步和阻塞是个包含关系,而不是同级关系,并不能构成同步阻塞等词汇。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值