zoukankan      html  css  js  c++  java
  • bio,nio,aio的区别 select,poll,epoll的区别

    先了解一些基本概念,什么是socket?什么是I/O操作
    • unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO、管道、终端,对我们来说,一切都是文件,一切都是流

    • 在信息交换的过程中,我们都是对这些流进行数据的收发操作,简称为I/O操作(input and output)

    • 计算机里有这么多的流,我怎么知道要操作哪个流呢?对,就是文件描述符,即通常所说的fd,一个fd就是一个整数,所以,对这个整数的操作,就是对这个文件(流)的操作。我们创建一个socket,通过系统调用会返回一个文件描述符,那么剩下对socket的操作就会转化为对这个描述符的操作

    然后看看一下几个概念
    1. BIO:同步阻塞IO,一个客户端连接,对应一个服务端线程

    2. BIO还有一种变种,伪异步IO,当有新的客户端接入时,将客户端的socket封装成一个task,丢到线程池中处理。优化了后续处理线程的方式

    3. NIO:同步非阻塞IO

    4. AIO:异步非阻塞IO(异步一定是非阻塞)

    再看看以下几个区别
    • 同步和异步针对应用程序来,关注的是程序中间的协作关系

    • 阻塞与非阻塞更关注的是单个进程的执行状态

    再看看I/O处理的过程
    • 数据通过网关到达内核,内核准备好数据

    • 数据从内核缓存写入用户缓存

    再来讲讲同步异步就清晰了
    • 同步:不管是BIO,NIO,还是IO多路复用,从内核缓存写入用户缓存一定是由 用户线程自行读取数据,处理数据

    • 异步:数据是内核写入的,并放在了用户线程指定的缓存区,写入完毕后通知用户线程

    • 阻塞:数据从网关写到内核,如果没写好,线程就一直在等待

    • 非阻塞:数据总网关写到内核,用一个线程轮询的去查看所有的数据是否准备好(I/O多路复用,监听多个socket)

    再来看看I/O多路复用的三种形式
    • select:知道了有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长

    • poll:本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的

    • epoll(Linux内核所特有):可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))(Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll)

    • 注意:表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调

    最后回来看看java内核的NIO的实现
    • 缓冲区Buffer

    1. 缓冲区实际上是一个数组,封装了对数据结构化访问以及维护读写位置等信息

    2. 在NIO库中,所有数据都是用缓冲区处理的,在读取数据时,直接读取到缓冲区。写入数据时,直接写入写缓冲区。任何时候访问NIO中的数据,都是 通过缓冲区进行操作

    3. 最常用的的缓冲区是ByteBuffer。大部分Java基本类型都对应一种缓冲区

    • 通道channel

    1. Channel 是一个通道,可以通过它读取和写入数据。InputStream和OutputStream各自只能在一个方向上操作

    2. Channel是全双工的,所以它可以比流更好地映射底层的api

    • 多路复用器Selector

    1. Selector是NIO的编程基础。多路复用器提供选择已经就绪的任务的能力

    2. Selector会不断轮询注册在其上的Channel,如果channel上面有了新的TCP连接、读取或者写事件,这个channel就是就绪状态,会被Selector轮询出来。然后通过SelectionKey集合可以获取就绪的Channel集合,进行IO操作

    3. 一个Selector可以同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,所以没有最大连接句柄1024/2048的限制。这意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端

    • NIO服务端序列图

    • NIO客服端序列图

    • 简单版本的交互图

  • 相关阅读:
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    SVN分支
    SVN分支
    SVN 版本回退
    SVN 版本回退
    如何在excel中取消合并单元格后内容自动填充?
    如何在excel中取消合并单元格后内容自动填充?
    如何让自己像打王者荣耀一样发了疯、拼了命的学习?
  • 原文地址:https://www.cnblogs.com/eryun/p/12040508.html
Copyright © 2011-2022 走看看