BIO、NIO、AIO的区别以及IO多路复用

这里直接引用一篇文章,个人感觉写的很好https://blog.csdn.net/peiyongwei/article/details/109990598

https://blog.csdn.net/qq_43416206/article/details/131405607

同步/异步以及阻塞/非阻塞的区别

1.1. Java IO读写原理
无论是Socket的读写还是文件的读写,在Java层面的应用开发或者是linux系统底层开发,都属于输入input和输出output的处理,简称为IO读写。在原理上和处理流程上,都是一致的。区别在于参数的不同。
用户程序进行IO的读写,基本上会用到read&write两大系统调用。可能不同操作系统,名称不完全一样,但是功能是一样的。
先强调一个基础知识:read系统调用,并不是把数据直接从物理设备,读数据到内存。write系统调用,也不是直接把数据,写入到物理设备。
read系统调用,是把数据从内核缓冲区复制到进程缓冲区;而write系统调用,是把数据从进程缓冲区复制到内核缓冲区。这个两个系统调用,都不负责数据在内核缓冲区和磁盘之间的交换。底层的读写交换,是由操作系统kernel内核完成的。

通过以上的描述,就会知道read和write并不是直接将物理设备的数据读取或写入到进程中,而是加了一个缓冲区,也就是说假如没有使用缓冲区。每次read|write系统调用都会进行一次内核状态的切换然后由操作系统的read|write系统调用线程将数据真实的传送到物理设备上,而加了缓冲区后,可以减少大部分操作系统内核切换的开销(操作系统内核态切换开销很大,需要保存当前进程的各种信息),从而这也就提高了性能。

有了以上对于read和write的理解,就可以解释同步和非同步了。

这里发表一些个人的拙见:同步|异步决定了用户线程与read/write系统调用线程是否能并发运行,而阻塞和非阻塞意味着read/write在数据没有准备好时能否继续阻塞等待,在同步不阻塞下,虽然用户需要等待系统调用完成,但是系统调用在没数据时时就会直接返回系统调用失败了,更不会阻塞咯。
在这里插入图片描述

同步|异步

同步就是指,read或者write系统调用在执行时,用户线程原来的代码是否能继续向下执行,但这与后面要说的阻塞|非阻塞不同,这里的执行是指read和write正在实实在在将内核缓冲区的数据拷贝到进程的缓冲区。
而异步就是指read和write正在实实在在将内核缓冲区的数据拷贝到进程的缓冲区时,主线程也仍然是可以执行自己的代码的,read和write在执行完数据的拷贝后,会通过某种方式告诉用户,比如回调,进程在调用read|write前给他一个回调函数的地址,让read|write操作完成后可以自动回调这里的函数。

同步IO的特点:
同步IO指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪。
同步IO的执行者是IO操作的发起者。
同步IO需要发起者进行内核态到用户态的数据拷贝过程,所以这里必须由个阻塞
异步IO的特点:
异步IO是指用户进程触发I/O操作以后就立即返回,继续开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知。
异步IO的执行者是内核线程,内核线程将数据从内核态拷贝到用户态,所以这里没有阻塞

大概可以理解为:同步IO:用户线程要读数据会自己去操作读取数据(当然要切换内核态),然后用户尝试读,直到读完了,就会继续执行下面的代码(逐行执行),而异步IO就是用户线程告诉另一个线程帮我去执行一些读取或者写入,然后另一个线程就会在读取完后反过来通知用户线程

阻塞|非阻塞

阻塞|非阻塞就是在发送完了系统调用请求后,原来的线程是否需要阻塞,非阻塞IO要求socket被设置为NONBLOCK,设置完成后,操作系统就会在数据还没准备完成时不阻塞线程(默认会阻塞线程知道数据拷贝完成),在内核缓冲区没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息。注意时调用失败,所以这并不与同步冲突


通过以上,大概就能知道,BIO模型和NIO模型的区别
首先,他们两个都会存在阻塞,因为他俩都是使用的同步的方式,只不过NIO会比BIO的阻塞更短,因为他阻塞只存在于在真实的拷贝数据的时候,而BIO会在调用系统调用的时候就直接阻塞住。


而基于NIO模型就有了IO多路复用模型,java中所说的NIO并不是刚刚所说的NIO模型而是new io,
目前支持IO多路复用的系统调用,有 select,epoll等等。select系统调用,是目前几乎在所有的操作系统上都有支持,具有良好跨平台特性。epoll是在linux 2.6内核中提出的,是select系统调用的linux增强版本。
在我看来这像是普通NIO模型的改进版,他通过单个线程不断的轮询select/epoll系统调用所负责的成百上千的socket连接,当某个或者某些socket网络连接有数据到达了,就返回这些可以读写的连接。因此,好处也就显而易见了——通过一次select/epoll系统调用,就查询到到可以读写的一个甚至是成百上千的网络连接。
而当select/epoll获取到返回数据后,就会再次进行read/write系统调用,这样就能减少几乎99%的阻塞时间,但是仍然会有一些阻塞,就是在read/write在拷贝数据时的阻塞,要去掉这一部分的阻塞,就需要用到异步io了,这通常就需要操作系统的底层进行配合,在拷贝完成数据后进行函数回调实现,至此就实现了AIO。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值