IO模型概述:同步阻塞、同步非阻塞、IO多路复用(异步阻塞)、异步IO //高并发系列

博文所在专栏里有更多相关内容,如JAVA NIO、Reactor反应器模式等,欢迎阅读与交流。
文字来源于读书笔记及个人心得,可能有引用其他博文,若引用了你的文字请联系我,我会加上来源,或者删除相关内容。

一 IO概述

(一)碎碎念

  1. 程序进行IO基本都会用到底层(操作系统)的read&write,只是调用方法的名称可能不同
  2. read&write操作不直接与物理设备交互,而是与缓冲区交互——read是把数据从(操作系统)内核缓冲区复制到进程缓冲区,write是进程到内核
  3. 传统IO模型都是同步阻塞IO;
  4. Java默认创建的socket都是阻塞的;
  5. Java的NIO是New IO,属于IO多路复用;
  6. 操作系统底层用一个文件描述符(fd:file descriptor)来表示一个网络连接;

(二)常见的四种IO模型:

同步阻塞IO(Blocking IO):

由用户空间的线程主动发起IO请求(同步),需要内核IO操作彻底完成后才返回到用户空间执行用户的操作(阻塞)。

阻塞IO特点:一次调用发起后,用户程序空间阻塞,等待内核缓冲数据准备好并复制到用户缓冲区,复制完返回给用户程序空间,才解除阻塞

阻塞IO的优点:开发简单,阻塞期间用户线程被挂起基本不占用CPU资源

阻塞IO缺点:每个线程维护一个IO操作,并发情况下就需要大量线程维护大量网络连接,内存、线程切换开销巨大

同步非阻塞IO(Non-blocking IO):

由用户空间的线程主动发起IO请求(同步),用户空间的程序不需要等待内核IO操作彻底完成,在接收到内核立即返回给用户的状态值后,即可返回用户空间执行用户的操作。

同步非阻塞IO特点:用户程序线程需不停发起IO调用,直到内核缓冲区准备好数据,这时再发起一次IO调用时,然后用户程序空间阻塞,直到数据从内核缓冲区复制到用户缓冲区并返回给用户程序空间,才解除阻塞

优点:在内核缓冲区等待/准备数据时用户发起的IO调用都不会阻塞,实时性较好

缺点:不停的轮询会占用大量CPU时间,效率低下,因此高并发场景也不会直接使用NIO

IO多路复用(IO Multiplexing)

也称为异步阻塞IO,一个线程可同时监视多个文件描述符(一个文件句柄表示一个网络连接)。

在IO多路复用模型中通过select/epoll系统调用,单个应用程序的线程,可以不断地轮询成百上千的socket连接,当某个或者某些socket网络连接有IO就 绪的状态,就返回对应的可以执行的读写操作。

IO多路复用有三种实现方式:select、poll、epoll,其中poll、epoll是linux的函数,而Linux 2.5.44版本后poll被epoll取代。select和poll的时间复杂度都是O(N),select是数组有大小限制,poll是链表无大小限制;epoll的时间复杂度是O(1)

优点:一个选择器查询线程可同时处理大量连接,系统不必创建和维护大量线程

缺点:select,poll,epoll本质上都是同步阻塞I/O,因为他们都需要在读写事件就绪后自己(系统调用)本身进行读写,也就是说这个读写过程是阻塞的

IO多路复用的read流程:

①将目标socket注册到select/epoll选择器;
②使用选择器查询方法返回就绪的socket列表,用户进程在调用select方法的时候是线程阻塞的;
③对就绪socket发起read系统调用,用户线程阻塞,内核开始复制数据;
④复制完成,内核返回结果给用户线程,用户线程读取到数据,解除阻塞。

异步IO(Asynchronous IO)

指系统内核是主动发起IO请求的一方,用户空间的线程是被动接受方。

也称信号驱动IO。用户线程通过系统调用,向内核注册某个IO操作,内核在整个IO操作(数据准备、复制)完成后,发送signal给用户线程。

内核的数据处理过程中用户程序都不需要阻塞。

缺点:用户程序仅需要注册“接收内核IO操作完成的事件”或回调函数并接收该事件,其余工作都留给了操作系统,需要底层内核提供支持。

(三)小小总结

同步阻塞IO开发简单,阻塞时不占用CPU,但每个线程维护一个IO操作,并发情况下内存、线程切换开销巨大;

同步非阻塞IO在内核准备数据期间不阻塞,实时性较好,但不停的轮询会占用大量CPU时间,效率低下;

IO多路复用(异步阻塞)一个线程可操作多个IO,但本质上读写过程是阻塞的;

异步IO对Windows系统是可以的,但在linux下目前仍不完善,底层仍使用的是与IO多路复用系统的epoll。

因此,Linux下的高并发程序IO目前更推荐使用IO多路复用模型。

(四)文件描述符

文件描述符(FileDescriptor、FD):文件句柄,也叫文件描述符。文件描述符是内核为了高效管理已被打开的文件所创建的索引,它 是一个非负整数(通常是小整数),用于指代被打开的文件。所有的IO系统调用,包括socket的读写调用,都是通过文件描述符完成的。
linux默认文件句柄数为1024。
在Linux系统中, 文件可分为:普通文件、目录文件、链接文件 和设备文件。
linux获取单个进程能打开的最大文件句柄数量:ulimit -n
临时修改:ulimit -n 10000
永久修改:编辑/etc/rc.local,添加一句话:ulimit -SHn 10000,该方式不可大于硬极限值
终极修改:编辑/etc/security/limits.conf,添加:
soft nofile 100000
hard nofile 100000

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值