Linux高级IO之五种IO模型

本篇博客主要介绍五种IO模型的基本概念、阻塞IO和非阻塞IO的区别、同步IO和异步IO的区别。

(一)IO的介绍

  • IO中的I是input输入的意思,O是output输出的意思,IO是基本输入输出设备;
  • 每个设备都由一个专用的I/O地址,用来处理自己的输入和输出信息。但记住:I/O地址绝对不能重复,如果两个设备的I/O地址有冲突,系统硬件就不能正常工作。

(二)IO模型

  • 对于一次IO访问(以read举例),数据先被拷贝到操作系统内核的缓冲区中。然后数据从操作系统内核的缓冲区拷贝到应用程序的地址空间。
  • 当read操作发生时,会经历两个阶段:1.等待数据准备。2.将数据从内核拷贝到进程中。
  • 因此,再网络编程环境中,一次IO操作主要包括两部分:等待数据准备+数据拷贝。
  • 如何提高IO效率:想办法减少等的比重。

五种IO模型

1.阻塞IO

以读事件为例:读事件不就绪时,系统调用以阻塞的方式等待。通俗的讲就是:在内核数据准备好之前,系统调用会一直等待。所有的套接字,默认都是阻塞方式。

具体过程:

(1)当用户进程调用了recvfrom这个系统调用,内核就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据一开始还没有到达。比如,还没有收到一个完整的UDP包,这个时候内核就要等待足够的数据到来。)这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区是需要一个过程的。而在用户进程这边,整个进程会被阻塞。

(2)当内核一直等到数据准备好了之后,就会将数据从内核中拷贝到用户内存,然后内核返回结果,用户进程才解除阻塞状态,重新运行起来。

2.非阻塞IO

非阻塞IO:如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回EWOULDBLOCK错误码。

非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询,但这个对CPU来说是较大的浪费,一般只有在特定场景下才使用。

一般非阻塞IO方式有两种:

  • 调用非阻塞接口.
  • 将文件描述符设置为非阻塞.

具体过程:

  • 当用户进程发出read操作时,如果内核中的数据还没准备好,那么它不会阻塞用户进程,而是立刻返回一个error.
  • 从用户角度看,用户发起一个read操作后,并不需要等待,而是马上就得到一个结果,用户进程判断结果是一个error,就知道数据还没准备好,于是用户可以再次发送read操作(这个反复尝试读写文件描述符的过程称为轮询).
  • 一旦内核中数据准备好了,并且又再次收到了用户进程的system call(系统调用),内核马上将数据拷贝到用户内存,然后返回.

3.信号驱动IO

信号驱动IO:内核将数据准备好了的时候,使用SIGIO信号通知应用程序进行IO操作.

具体过程:

  • 首先开启套接字接口信号驱动I/O功能,并通过系统调用sigaction执行一个信号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的).
  • 当数据准备就绪时,就为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据,并通知主循环函数处理数据.

4.IO多路转接

实现select版本的TCP服务器

https://blog.csdn.net/tangya3158613488/article/details/97933011

IO多路转接:虽然从流程图上看起来和阻塞IO类似.实际上最核心在于IO多路转接能够同时等待多个文件描述符的就绪状态.

5.异步IO

异步IO:由内核在数组拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝).

具体过程:

  • 用户进程发起read操作之后,立即就可以考虑做其他的事.
  • 而另一方面,从内核的角度,当它收到一个asynchronous read之后,首先它会立即返回,所以不会对进程产生任何阻塞.
  • 然后,内核会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,内核会给用户进程发送一个signal,告诉用户read操作完成了.

同步IO包括:阻塞IO,非阻塞IO,信号驱动IO,IO多路转接

高级IO模型总结

任何IO过程,都包含两个步骤:第一是等待,第二是拷贝.而且在实际的应用场景中,等待消耗的时间往往都远高于拷贝的时间,让IO更高效,最核心的办法就是让等待时间尽量少.实际上,从硬盘中读数据,需要定位硬盘的磁道等过程,这个过程是需要等待的,所以也要消耗大量时间.

同步通信 vs 异步通信

同步和异步关注的是消息通信机制.

  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就得到返回值了; 换句话说,就是由调用者主动等待这个调用的结果.
  • 异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果; 换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果; 而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用. 

值得注意的是:在学习多进程多线程的时候,也提到同步和互斥.这里的同步通信和进程之间的同步完全是不相干的两个概念.

  • 进程/线程同步也是进程/线程之间直接的制约关系.
  • 是为了完成某种任务而建立的两个或多个线程,这个线程需要在某个位置上协调它们的工作次序而等待\传递信息所产生的制约关系,尤其是在访问临界资源的时候.

阻塞 vs 非阻塞

阻塞和非阻塞的区别:在于等待的方式不同.

  • 阻塞调用是指第哦啊用结果返回之前,当前线程会被挂起.调用线程只有在得到结果之后才会返回.
  • 非阻塞调用指在不能立即得到结果之前,该调用不会阻塞当前线程.

举例理解五种IO模型

(1)阻塞IO模型:

    张三在钓鱼,在鱼没有上钩之前,他便一直坐在小马扎上等;当鱼上钩一瞬间,将鱼取上来.而在这期间,他一直在等,不做任何事情.

(2)非阻塞IO模型:

    李四也来到鱼塘钓鱼,李四的做法是:当鱼没有上钩之前,他去干点其他事情,比如玩玩手机或和别人聊天.当鱼上钩时,将鱼钓上来.这时他确实是自己等待了,但是期间没有一直等待,而是在等待的过程中做了其他事情.

(3)信号驱动IO模型:

   王五来到鱼塘钓鱼,他在鱼竿上放了一个铃铛,当鱼上钩是,铃铛会响,在铃铛响起之前,他可以干自己的事情,当铃铛响起时,他立马去把鱼钓上来.

(4)IO多路转接:

   赵六来到鱼塘钓鱼,他将一百个鱼竿放到鱼塘里,然后依次检查这些鱼竿上是否有鱼上钩,当有一个鱼竿上有鱼时,将鱼取出,然后继续检查所有鱼竿.

   显然这种钓鱼方式效率很高,因为别人都是一人拿一支鱼竿,而赵六用了100个鱼竿,从钓到鱼的角度,100个鱼竿中,赵六的鱼竿被鱼咬住的几率更大.

(5)异步IO模型:

   田七准备钓鱼,但他并没有自己去调,而是雇了一个人去帮他钓鱼.他自己去干其他事情.整个钓鱼过程,田七并没有参与,也没有等待.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值