zoukankan      html  css  js  c++  java
  • 图解I/O的五种模型

    1.1 五种I/O模型  

    1)阻塞I/O

    2)非阻塞I/O

    3)I/O复用

    4)事件(信号)驱动I/O

    5)异步I/O

    1.2 为什么要发起系统调用? 

    因为进程想要获取磁盘中的数据,而能和磁盘打交道的只能是内核, 进程通知内核,说要磁盘中的数据

    此过程就是系统调用 

     

    1.3 一次I/O完成的步骤

    当进程发起系统调用时候,这个系统调用就进入内核模式, 然后开始I/O操作

    I/O操作分为俩个步骤: 

             1) 磁盘把数据装载进内核的内存空间

             2) 内核的内存空间的数据copy到用户的内存空间中(此过程才是真正I/O发生的地方) 

    注意: io调用大多数都是阻塞的

     过程分析

           整个过程:此进程需要对磁盘中的数据进行操作,则会向内核发起一个系统调用,然后此进程,将会被切换出去,

    此进程会被挂起或者进入睡眠状态,也叫不可中 断的睡眠,因为数据还没有得到,只有等到系统调用的结果完成后,

    则进程会被唤醒,继续接下来的操作,从系统调用的开始到系统调用结束经过的步骤:

    ①进程向内核发起一个系统调用,

    ②内核接收到系统调用,知道是对文件的请求,于是告诉磁盘,把文件读取出来

    ③磁盘接收到来着内核的命令后,把文件载入到内核的内存空间里面

    ④内核的内存空间接收到数据之后,把数据copy到用户进程的内存空间(此过程是I/O发生的地方)

    ⑤进程内存空间得到数据后,给内核发送通知

    ⑥内核把接收到的通知回复给进程,此过程为唤醒进程,然后进程得到数据,进行下一步操作

    2.1 阻塞

        是指调用结果返回之前,当前线程会被挂起(线程进入睡眠状态函数只有在得到结果之后,才会返回,才能继续执行

    阻塞I/O系统怎么通知进程? 

    I/O 完成后, 系统直接通知进程, 则进程被唤醒   

    第一阶段是指磁盘把数据装载到内核的内存中空间中

    第二阶段是指内核的内存空间的数据copy到用户的内存空间 (这个才是真实I/O操作)

    2.2 非阻塞

      非阻塞:进程发起I/O调用,I/O自己知道需过一段时间完成,就立即通知进程进行别的操作,则为非阻塞I/O

    非阻塞I/O,系统怎么通知进程?

    每隔一段时间,问内核数据是否准备完成,系统完成后,则进程获取数据,继续执行(过程也称盲等待)

    缺点无法处理多个I/O,比如用户打开文件,ctrl+C想终止这个操作,是无法停掉的

                第一阶段是指磁盘把数据装载到内核的内存中空间中

                第二阶段是指内核的内存空间的数据copy到用户的内存空间 (这个才是真实I/O操作)

    2.3 I/O多路复用 select

    为什么要用I/O多路复用

      某个进程阻塞多个io ,一个进程即要等待从键盘输入信息另一个准备从硬盘装入信息

    比如通过read这样的命令调用了来个io操作,一个io完成了,一个io没有完成阻塞着键盘io,磁盘io完成了 ,

    这个进程也是不能响应因为键盘io还没有完成,还在阻塞着 , 这个进程还在睡眠状态 ,这个时候怎么办 ?

    由此需要I/O多路复用。

    执行过程

           以后进程在调用io的时候不是直接调用io的功能,在系统内核中新增了一个系统调用帮助进程监控多个io,

    一旦一个进程需要系统调用的时候向内核的一个特殊的系统调用,发起申请时,这个进程会被阻塞在这个复用器的调用上,

    所以复用这个功能会监控这些io操作,任何一个io完成了,它都会告诉进程,其中某个io完成,如果进程依赖某个io操作,

    那么这个时候,进程就可以继续后面的操作能够帮组进程监控这些io的工具叫做io复用器

    Linux中  I/O 复用器

    select: 就是一种实现,进程需要调用的时候,把请求发送给select ,可以发起多个,但是最多只能支持1024,先天性的限制  

    poll: 没有限制,但是多余1024个性能会下降

    所以早期的apache 本身prefork mpm模型,主进程在接受多个用户请求的时候,在线请求数超过1024,就不工作了.

    那么io复用会比前俩种好吗?

      本来进程和系统内核直接沟通的 ,在中间加一个i/o复用select, 如果是传话,找人传话,那么这个传话最后会是什么样的呢?

    虽然解决了多个系统调用的问题,多路io复用本身的后半段依然是阻塞的,阻塞在select 而不是阻塞在系统调用上,

    但是他第二段仍然是阻塞的,由于要扫描所有多个io操作多了一个处理机制,性能未必上升性能上也许不会有太大的改观

            
                        一阶段是指磁盘把数据装载到内核的内存中空间中

                                            第二阶段是指内核的内存空间的数据copy到用户的内存空间 (这个才是真实I/O操作) 

    2.4 事件驱动 

    进程发起调用,通过回调函数内核会记住是那个进程申请的,一旦第一段完成了,就可以向这个进程发起通知,

    这样第一段就是非阻塞的,进程不需要盲等了但是第二段依然是阻塞的

    事件驱动机制(event-driven)

    正是由于事件驱动机制 ,才能同时相应多个请求的

    比如一个web服务器一个进程响应多个用户请求

    缺陷第二段仍然是阻塞的

    俩种机制

    如果一个事件通知一个进程,进程正在忙进程没有听见这个怎么办?

    水平触发机制: 内核通知进程来读取数据,进程没来读取数据,内核需要一次一次的通知进程

    边缘触发机制: 内核只通知一次让进程来取数据,进程在超时时间内,随时可以来取数据, 把这个事件信息状态发给进程,好比发个短息给进程,

    nginx

         nginx默认采用了边缘触发驱动机制 

        

    第一阶段是指磁盘把数据装载到内核的内存中空间中

    第二阶段是指内核的内存空间的数据copy到用户的内存空间 (这个才是真实I/O操作)

    2.5 异步AIO

    无论第一第二段不再向系统调用提出任何反馈只有数据完全复制到服务进程内存中后才向服务进程返回ok的信息,其它时间,

    进程可以随意做自己的事情,直到内核通知ok信息

    注意: 只在文件中可以实现AIO, 网络异步IO 不可能实现

    nginx:
    nginxfile IO 文件异步请求的
    一个进程响应N个请求
    静态文件界别支持sendfile   
    避免浪费复制时间:  mmap 支持内存映射,内核内存复制到进程内存这个过程不需要复制了直接映射到进程内存中
    支持边缘触发
    支持异步io
    解决了c10k的问题
    c10k : 有一万个同时的并发连接
    c100k: 你懂得

    第一阶段是指磁盘把数据装载到内核的内存中空间中

    第二阶段是指内核的内存空间的数据copy到用户的内存空间 (这个才是真实I/O操作)

    前四种I/O模型属于同步操作,最后一个AIO则属于异步操作 

    2.6 五种模型比较

    同步阻塞

    俩段都是阻塞的,所有数据准备完成后,才响应

    同步非阻塞

    磁盘从磁盘复制到内核内存中的时候不停询问内核数据是否准备完成盲等

    性能有可能更差 ,看上去他可以做别的事情了但是其实他在不停的循环

    但还是有一定的灵活性的

    缺点无法处理多个I/O,比如用户打开文件,ctrl+C想终止这个操作,是无法停掉的

    同步IO

    如果第二段是阻塞的 ,代表是同步的

    第一种,第二种,io复用,事件驱动,都是同步的.  

    异步IO

    内核后台自己处理 ,把大量时间拿来处理用户请求

     



    本文是纯属个人学习理解,如有遗漏误导,请大神果断指正......
  • 相关阅读:
    jenkins 使用oclint 扫描 oc 代码
    mac下 jenkins 环境搭建
    jenkins 中 Poll SCM 和 Build periodically 的区别
    表单验证封装,一招学会,永远受用
    浅谈js中的执行环境和执行环境对象
    浅谈php之设计模式基础
    四条地铁线带你通往Ajax的大门
    论js结合数学的应用
    以留言本的开发打开ajax的世界
    初步学习css3之3D动画
  • 原文地址:https://www.cnblogs.com/budongshu/p/5117584.html
Copyright © 2011-2022 走看看