Linux Nginx服务器 五种IO模型

1.什么是IO

IO在计算机中指Input/Output,也就是输入和输出。由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘、网络等,就需要IO接口。

比如你打开浏览器,访问腾讯首页,浏览器这个程序就需要通过网络IO获取腾讯的网页。浏览器首先会发送数据给腾讯服务器,告诉它我想要首页的HTML,这个动作是往外发数据,叫Output,腾讯服务器把网页发过来,这个动作是从外面接收数据,叫Input。所以,通常,程序完成IO操作会有Input和Output两个数据流。当然也有只用一个的情况,比如,从磁盘读取文件到内存,就只有Input操作,反过来,把数据写到磁盘文件里,就只是一个Output操作。

I/O操作是相对于内存而言的,从外部设备进入内存就叫Input,反之从内存输出到外部设备就叫Output
通常用户进程中的一个完整IO分为两阶段:用户进程空间<- ->内核空间、内核空间<- ->设备空间(磁盘、网络等)。IO有内存IO、 网络IO和磁盘IO三种,通常我们说的IO指的是后两者。

I/O按照设备来分的话,分为两种,其一是网络I/O,也就是通过网络进行数据的拉取和输出。还有一种是磁盘I/O,主要是对磁盘进行读写工作。

LINUX中进程无法直接操作I/O设备,其必须通过系统调用请求kernel来协助完成I/O动作;内核会为每个I/O设备维护一个缓冲区。
对于一个输入操作来说,进程IO系统调用后,内核会先看缓冲区中有没有相应的缓存数据,没有的话再到设备中读取,因为设备IO一般速度较慢,需要等待;内核缓冲区有数据则直接复制到进程空间。
所以,对于一个网络输入操作通常包括两个不同阶段:

  • 等待网络数据到达网卡→读取到内核缓冲区,数据准备好;
  • 从内核缓冲区复制数据到进程空间

2.什么是用户空间和内核空间

虚拟内存被操作系统划分成两块:内核空间和用户空间。
为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。
内核空间是内核代码运行的地方,用户空间是用户程序代码运行的地方。
当进程运行在内核空间时就处于内核态,当进程运行在用户空间时就处于用户态。

3.什么是同步和异步

由于CPU和内存的速度远远高于外设的速度。所以在IO编程中,就存在速度严重不匹配的问题。

举个例子:

我们都是通过热水壶来烧水的。在很久之前,科技还没有这么发达的时候,如果我们要烧水,需要把水壶放到火炉上,我们通过观察水壶内的水的沸腾程度来判断水有没有烧开。

随着科技的发展,现在市面上的水壶都有了提醒功能,当我们把水壶插电之后,水壶水烧开之后会通过声音提醒我们水开了。

传统水壶的烧水就是同步的,电热水壶的烧水就是异步的。

  • 同步请求:A调用B,B的处理是同步的,在处理完之前他不会通知A,只有处理完之后才会明确的通知A。

  • 异步请求:A调用B,B的处理是异步的,B在接到请求后先告诉A我已经接到请求了,然后异步去处理,处理完之后通过回调等方式再通知A。

同步和异步最大的区别就是被调用方的执行方式和返回时机。同步指的是被调用方做完事情之后再返回,异步指的是被调用方先返回,然后再做事情,做完之后再想办法通知调用方。

4.什么是阻塞和非阻塞

仍然用上面的例子来说:当你把水放到水壶里面,按下开关后,你可以坐在水壶前面,别的事情什么都不做,一直等着水烧好。你还可以先去客厅看电视,等着水开就好了。

对于你来说,坐在水壶前面等就是阻塞的,去客厅看电视等着水开就是非阻塞的。

  • 阻塞请求:A调用B,A一直等着B的返回,别的事情什么也不干。

  • 非阻塞请求:A调用B,A不用一直等着B的返回,先去忙别的事情了。

阻塞和非阻塞最大的区别就是在被调用方返回结果之前的这段时间内,调用方是否一直等待。阻塞指的是调用方一直等待别的事情什么都不做。非阻塞指的是调用方先去忙别的事情。

5.阻塞IO模型

进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个IO处理完毕后返回进程。操作成功则进程获取到数据
在这里插入图片描述
在这里插入图片描述

小明去火车站买票,排队三天买到一张退票。
耗费:在车站吃喝拉撒睡3天,其他事一件没干

6.非阻塞IO模型

进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。
对于上面的阻塞IO模型来说,内核数据没准备好需要进程阻塞的时候,就返回一个错误,以使得进程不被阻塞
在这里插入图片描述

小明去火车站买票,隔12小时去火车站问有没有退票,三天后买到一张票。
耗费:往返车站6次,路上6小时,其他时间做了好多事

7.IO复用模型

多个的进程的IO可以注册到一个复用器(select)上,然后用一个进程调用该select,,select会监听所有注册进来的IO
在这里插入图片描述

如果select没有监听的IO在内核缓冲区都没有可读数据,select调用进程会被阻塞;而当任一IO在内核缓冲区中有可数据时,select调用就会返回;而后select调用进程可以自己或通知另外的进程(注册进程)来再次发起读取IO,读取内核中准备好的数据
典型应用:select、 poll、 epoll三种方案,nginx都可以选择使用这三个方案

Linux中IO复用的实现方式主要有select,poll和epoll:

  • Select:注册IO、阻塞扫描,监听的IO最大连接数不能多于FD_ SIZE(1024)
  • Poll:原理和Select相似,没有数量限制,但IO数量大扫描线性性能下降
  • Epoll :事件驱动不阻塞,mmap实现内核与用户空间的消息传递,数量很大,Linux2.6后内核支持

select/poll:
小明去火车站买票,委托黄牛,黄牛三天内买到票,然后打便所有人要买票人的电话找到小明,小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,等待通知3小时

epoll:
小明去火车站买票,委托黄牛,黄牛买到后即通知小明去领,然后小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话

8.信号驱动IO模型

当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据
在这里插入图片描述

小明去火车站买票,给售票员留下电话,有票后,售票员电话通知小明,然后小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,免黄牛费100元,无需打电话

9.异步IO模型

当进程发起一个IO操作,进程返回(不阻塞),但也不能返回结果;内核把整个IO处理完后,会通知进程结果。如果IO操作成功则进程直接获取到数据
在这里插入图片描述

小明去火车站买票,给售票员留下电话,有票后,售票员电话通知小明并快递送票上门。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话

注意:
此模型和前面模型最大的区别是:前4个都是阻塞的,因为需要自己把用户准备好的数据,放在我的用户空间,而全异步都帮我们做好了。
用户线程完全不需要关心实际的整个IO操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示IO操作已经完成,可以直接去使用数据了。它是最理想的模型

10.5种IO模型的区别

在这里插入图片描述

发布了107 篇原创文章 · 获赞 0 · 访问量 1429

猜你喜欢

转载自blog.csdn.net/weixin_45029822/article/details/104532489