作为一名程序员,io知识是必不可少,其实一直在和io打交道,要么显示要么隐含给了操作系统,故做下关于io的记录。说io之前呢,先介绍什么叫同步异步丶阻塞非阻塞
1. 同步异步丶阻塞非阻塞
1.1 同步是指发出一个请求,在没有得到结果之前该请求就不返回结果,请求返回时,也就得到结果了。比如我经常用烧水壶烧水,没烧开前一直盯着水壶(等水开)。
1.2 异步是指发出一个请求后,立刻得到了回应,但没有返回结果,这时我们可以再处理别的事情(发送其他请求),所以这种方式需要我们通过状态主动查看是否有了结果, 或者可以设置一个回调来通知调用者。比如烧水时,不需要盯着水壶等水开,也可以做别的事:玩电脑,每两三分钟(类似轮询任务)看看水开了没有,也可以给水壶设置响铃(信号通知,发邮件发短信),水开了通知了我(don’t call me,I call you)。
1.3 阻塞是指请求结果返回之前,当前线程会被挂起(被阻塞),线程什么也做不了了,而非阻塞是指请求结果返回之前,当前线程没有被阻塞,仍然可以做其他事情。
2. IO模型
一个io请求读操作,数据会先被拷贝到操作系统内核的缓冲区中,然后从操作系统内核的缓冲区拷贝到应用程序的地址空间,所以整个过程可分为两个阶段:等待I/O数据准备好,这取决于IO目标返回数据的速度, 如网络IO时看网速和数据本身的大小;数据从内核缓冲区拷贝到进程内。
模型分类可分为以下几种:BIO,NIO,IO多路复用,AIO,我就一一简单介绍下
2.1 BIO
BIO,全称是Blocking I/O,中文名叫:
阻塞 I/O,整个过程如图:
应用程序发送请求给内核,然后由内核去进行通信,在内核准备好数据之前这个线程是被挂起的,所以在两个阶段程序都处于挂起状态, 其 特点就是在IO执行的两个阶段都被block了 。
2.2 NIO
NIO,全称是Non-Blocking IO,中文名字叫非阻塞IO,过程如图示:
发起第一次请求后,线程并没有被阻塞,它反复检查数据是否准备好,把原来大块不能用的阻塞时间分成了许多“小阻塞”(检查),所以进程不断有机会被执行。这个检查有没有准备好数据的过程有点类似于“轮询”。其特点就是程序需要不断的主动询问内核数据是否准备好。第一个阶段非阻塞,第二个阶段阻塞。
2.3 IO多路复用(重点,此模型不少中间件都用到了)
IO多路复用(I/O Multiplexing
)有select
,poll
,epoll
等不同方式,它的优点在于单个线程可以同时处理多个网络IO。不同于NIO
中轮询操作是用户线程进行的,而IO多路复用
调用操作系统级别的select
或poll或epoll
模型,由系统进行监控IO状态。select轮询可以监控许多socket的IO请求,当有一个socket的数据准备好时就可以返回。多路复用IO过程图:
与NIO不同的是,select不是等到所有数据准备好才返回,而是只要有一个准备好就返回,它的强项在于可以同时处理多个连接。 其 特点是用户进程能同时等待多个IO请求,系统来监控IO状态,其中的任意一个进入读就绪状态,select函数就可以返回。 nio在java1.4才引入
2.4 AIO
AIO全称是Asynchronous I/O,中文名叫:
异步 I/O,它是Java1.7 才引入。整个过程中,用户线程发起一个系统调用之后无须等待,可以处理别的事情。由操作系统等待接收内容,接收后把数据拷贝到用户进程中,最后通知用户程序已经可以使用数据了,两个阶段都是非阻塞的。整个过程如下图
Java中可通过以下两种方式实现:
一种是基于”回调”,我们可以实现CompletionHandler接口,在调用时把回调函数传递给对应的API即可;
一种是返回一个Future。处理完别的事情,可以通过isDone()可查看是否已经准备好数据,通过get()方法等待返回数据。
好了,暂且就写这么多,多多交流探讨
参考:
1. OReilly.Java.I.O.2nd.Edition.May.2006
2. Unix网络编程卷1(几种io模型)