Linux I/O模型(以吃牛肉面为例)

一、前言

同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,有什么区别,为什么性能差别巨大,结合我个人的理解做一下总结。(仅讨论linux场景下)
知识点说明:

用户(进程)空间和内核空间:
操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户(进程)空间。

标准 I/O

缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。linux上偶尔因程序异常占用大量内存,需手动释放page cache,echo 1 > procsys/vm/drop_caches,就是因为这个原因。

标准 I/O 的缺点:
数据在传输过程中需要在应用程序地址空间和内核进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的。例如socket在传输数据包时为了防止过于频繁的传输,有时会将一些小的数据包整合在一起一次性发,导致socket粘包。

二.I/O模式

对于一次系统IO的访问,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间,即从kernel空间copy到用户空间。所以说,当一个read操作发生时,它会经历两个阶段:

  1. Input,等待数据进入内核空间 (Waiting for the data to be ready)
  2. Output,将数据从内核空间拷贝到进程空间中 (Copying the data from the kernel to the process)

正式因为这两个阶段,linux系统产生了下面五种网络模式的方案。

  • 同步阻塞 I/O(blocking IO)
  • 同步非阻塞 I/O(nonblocking IO)
  • I/O 多路复用( IO multiplexing)
  • 信号驱动 I/O( signal driven IO)
  • 异步 I/O(asynchronous IO)

注:signal driven IO在实际中比较少用,所以我只说明其余四种Model。

1.同步阻塞 I/O(blocking IO)
在linux中,默认情况下所有的socket都是blocking,一个典型的流程图:
这里写图片描述

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

3.I/O多路复用:
IO multiplexing就是我们说的select,poll,epoll,有些地方也称这种IO方式为event driven IO。select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。性能强大的模型,典型案例就是nginx,使用epoll模型的nginx单点支撑5W并发非常轻松。
这里写图片描述
select的优势在于它可以同时处理多个connection。如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-thread + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)

在IO multiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个process的上半部分其实是一直被block的(即向kernel发起select调用的部分),需要等kernel回复之后,再向kernel发起一个内核态向用户态copy数据的系统调用,发起这个调用后,process就可以进行context switch了,这个时候内核需要进行的工作是将数据从内核态复制到用户态(即I/O)。因此对于process而言,这种模型即为I/O复用。

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

看的很费劲?OK,那就自己动手画几张形象生动点的图吧,身为吃货当然以“吃”举例

1.同步阻塞 I/O(blocking IO)
这里写图片描述

2.同步非阻塞I/O:
这里写图片描述

3.I/O多路复用:
这里写图片描述

4.异步I/O:
这里写图片描述

感觉心里想着牛肉面,这几个模型都好理解了,Over~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值