• 理解同步,异步,阻塞,非阻塞,多路复用,事件驱动IO


    以下是IO的一个基本过程

     

    先理解一下用户空间和内核空间,系统为了保护内核数据,会将寻址空间分为用户空间和内核空间,32位机器为例,高1G字节作为内核空间,低3G字节作为用户空间。当用户程序读取数据的时候,会经历两个过程:磁盘到内核空间(这块消耗性能,下面简称内核数据准备),内核空间拷贝到用户空间(下面简称用户空间拷贝)。

     

    内核数据准备这部分是由DMA芯片实现的,而用户空间拷贝的实现则是由CPU实现的,后者非常快,能到1G以上,所以,所谓的阻塞基本是内核数据准备的过程,这块消耗时间。为啥呢?简单的理解就是,磁盘和内核缓存的速度本身就存在很大的差距。

    基于这个前提,聊一下同步异步IO,阻塞非阻塞IO

    同步异步是基于任务序列可靠性的角度区分,当一个任务依赖另外一个任务时,

    同步就是,只有等被依赖的任务完成之后,依赖任务才算完成,是一种可靠任务序列。比如打电话。

    异步就是,只是通知被依赖任务去做某件事情,由被依赖任务完成之后通知依赖任务,但是不能保证被依赖任务完成,是一个不可靠任务序列。比如发短信。

    同步异步的选择其实就是可靠性和性能之前的取舍和平衡。

    而阻塞非阻塞则是从CPU消耗的角度去区分

    阻塞就是让CPU闲置,等IO等慢操作完成之后再继续。

    非阻塞则是在等IO等慢操作的完成的同时,CPU去做一些其他事情。存在上下文切换。

    阻塞非阻塞的选择就是在CPU利用率和系统切换成本之间的平衡。

    上面四者两两组合情况如下

    接下来了解一下linux下的几种IO模型

    当我们进行IO操作的时候,如果被调用者将任务全部执行完返回,称为同步/阻塞 IO

     

    如果被调用者,不管没有操作成功,直接返回一个结果码,但是不再主动通知后续结果,称为非阻塞IO;这种情况下需要重复调用查询状态。

     

    如果被调用者,不管有没有操作成功,直接返回个结果码,等到全部操作完成之后再发一个信号通知调用者,称为异步IO

    举个例子:

    家里有个专门帮忙做饭的阿姨,有一天我想喝水了,我让阿姨帮忙烧一壶水。

    我看着她去烧水,灌水,给我倒水,期间没有做其他任何事情,这就是同步。

    我想着也不用一直等,可以先看会儿电视,我就隔一会儿来看一次,隔一会儿来看一次,这叫非阻塞。

    再想想,这也烦,我索性跟阿姨说,好了叫我一声,然后就去看电视去了,这叫异步。

    而IO多路复用,信号驱动IO则是基于前面四个模型的衍生。

    IO多路复用是基于阻塞IO的衍生,主要是为了提高内核空间数据准备这一块的功能复用,即阻塞的同时监听多个端口,有一个端口有数据就进行处理,提高性能。

    信号驱动IO则是在内核空间数据准备这一块采用异步,在用户空间拷贝这一块采用同步。

     

    Java中的IO则分为以下几种

    同步阻塞IO(Java IO)

    l  用户进程发起一个IO操作之后,必须等待IO操作完成。

    同步非阻塞IO(Java NIO)

    l  用户发起一个IO操作之后,返回做其他事情,时不时的去询问IO是否就绪。

    多路复用IO

    l  用户发起一个IO操作之后,返回,等内核完成IO之后通知应用程序,这里的阻塞是指返回之后并没有做其他是,而是一并监听多个文件句柄,在select函数中,提高系统并发性。

    异步非阻塞IO(Java NIO2)

    l  用户发起一个IO操作之后,返回,等待 内核数据准备 和 用户空间拷贝都完成之后通知应用进程,中有实现。

    NIO中的概念

    Buffer:高效的数据容器,除了布尔类型,所有数据类型都有相应的Buffer实现。

    Channel:作用类似Linux系统中的文件描述符,是用于支持抽象批量IO的一种抽象。相对于File/Socket:Channel是更加接近操作系统底层的一种抽象。

    Selector:是NIO中多路复用的基础,可以同时检测注册在Selector上的多个Channel,进而对准备好的任一Channel进行处理。(这部分在linux中依赖epoll,windows上依赖iocp)

    Charset,提供了字符编解码器,可以实现字符到ByteBuffer的转换。

    内存映射:可以将内核空间地址和用户空间地址映射到同一物理地址

    零拷贝技术:数据只在内核空间流转,没有经过用户空间。

     

  • 相关阅读:
    3.1《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——下载文件
    rem实现手机页面自动缩放
    Git 常用命令
    使用 canvas+JS绘制钟表
    JS 操作数组的方法
    Node.js Request方法
    兼容浏览器的点击事件
    ES6知识点
    上传项目到github上
    JavaScript 编码风格
  • 原文地址:https://www.cnblogs.com/darrenqiao/p/9311618.html
Copyright © 2020-2023  润新知