当前位置:网站首页>阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一文搞定
阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一文搞定
2022-06-23 15:33:00 【InfoQ】
1 阻塞跟非阻塞
1.1 阻塞

- CPU把数据从磁盘读到内核缓冲区。
- CPU把数据从内核缓冲区拷贝到用户缓冲区。
1.2 非阻塞

1.3 IO多路复用


1.3.1 select
- select 会修改传入的参数数组,这个对于一个需要调用很多次的函数,是非常不友好的。
- select 如果任何一个sock(I/O stream)出现了数据,select 仅仅会返回,但不会告诉是那个sock上有数据,只能自己遍历查找。
- select 只能监视1024个链接。
- select 不是线程安全的,如果你把一个sock加入到select, 然后突然另外一个线程发现这个sock不用,要收回,这个select 不支持的。
1.3.2 poll
- poll 去掉了1024个链接的限制。
- poll 从设计上来说不再修改传入数组。
1.3.3 epoll
- epoll 现在是线程安全的。
- epoll 现在不仅告诉你sock组里面数据,还会告诉你具体哪个sock有数据,你不用自己去找了。
- epoll 内核态管理了各种IO文件描述符, 以前用户态发送所有文件描述符到内核态,然后内核态负责筛选返回可用数组,现在epoll模式下所有文件描述符在内核态有存,查询时不用传文件描述符进去了。
1.3.4 三者对比

1.4 异步IO

【文章福利】另外小编还整理了一些C++后端开发面试题,教学视频,后端学习路线图免费分享,需要的可以自行添加:
学习交流群点击加入~
群文件共享
小编强力推荐C++后端开发免费学习地址:
C/C++Linux服务器开发高级架构师/C++后台开发架构师

2 同步跟异步
2.1 同步
- 同步阻塞:此时一个线程维护一个连接,该线程完成数据到读写跟处理到全部过程,数据读写时时线程是被阻塞的。
- 同步非阻塞:非阻塞的意思是用户线程发出读请求后,读请求不会阻塞当前用户线程,不过用户线程还是要不断的去主动判断数据是否准备OK了。此时还是会阻塞等待内核复制数据到用户进程。他与同步BIO区别是使用一个连接全程等待

2.2 异步

2.3 同步跟异步对比
3 Java IO
- BIO:同步阻塞IO。
- NIO:同步非阻塞IO。
- AIO:异步非阻塞IO。
3.1 BIO

- 使用一个独立的线程维护一个socket连接,随着连接数量的增多,对虚拟机造成一定压力。
- 使用流来读取数据,流是阻塞的,当没有可读/可写数据时,线程等待,会造成资源的浪费。
3.1.1 BIO 样例
public class Constant {
public static final String HOST = "127.0.0.1";
public static final int PORT = 8080;
}public class ClientMain {
public static void main(String[] args) {
//开启服务
System.out.println("开启服务,监听端口:" + Constant.PORT);
new Thread(new ServerThread()).start();
//建立一个socket客户端,发起请求
System.out.println("客户端,请求连接,并发送数据");
try {
Socket socket = new Socket(Constant.HOST,Constant.PORT);
//开启新的线程处理socket连接
new Thread(new ClientProcessThread(socket)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}// 开启服务监听线程,当收到连接请求后,开启新的线程进行处理
public class ServerThread implements Runnable{
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(Constant.PORT);
while (true){
Socket socket = serverSocket.accept();
new Thread(new ServerProcessThread(socket)).start();
//开启新的线程进行连接请求的处理
}
} catch (IOException e) {
e.printStackTrace();
}
}
}import java.io.*;
import java.net.Socket;
/**
* 服务端收到连接请求后,处理请求的线程,阻塞式IO
*/
public class ServerProcessThread implements Runnable {
private Socket socket;
public ServerProcessThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
//获取客户端的数据,并写回
//等待响应
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
String requestStr = "";
System.out.println("来自客户端的数据:"); // 读取客户端数据
while((line = bufferedReader.readLine()) != null){
requestStr += line;
System.out.println(line);
}
// 从服务端发给客户端数据
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("data from server " + requestStr + "\r\n");
writer.flush();
writer.close();
bufferedReader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}/**
* 维护客户端socket连接的线程,阻塞式IO
*/
public class ClientProcessThread implements Runnable {
private Socket socket;
public ClientProcessThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
//写数据,等待响应,输出响应
String requestStr = "data from client \r\n";
try {
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write(requestStr);
writer.flush();
socket.shutdownOutput();
//等待响应
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
System.out.println("来自服务端的响应:");
while((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
writer.close();
bufferedReader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 NIO

- 不必对每个连接分别创建线程。
- 数据读写非阻塞。
- selector:Selector 允许单线程处理多个Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。要使用Selector,得向Selector注册Channel,然后调用他的select方法,这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子入有新连接接进来,数据接收等。
- Channel:基本上所有的IO在NIO中都从一个Channel开始。Channel有点像流,数据可以从channel读到buffer,也可以从buffer写到channel。
- Buffer:缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组),该对象提供了一组方法,可以更轻松的使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变换情况,Channel提供从文件,网络读取数据的渠道,但是读取或者写入的数据都必须经由Buffer。
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannelByteBuffer
CharBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
3.3 AIO
参考资料

边栏推荐
- CA认证和颁发吊销证书
- 图片读取:Image.open(ImgPath)
- Important knowledge of golang: waitgroup parsing
- 【TcaplusDB知识库】Tmonitor后台一键安装介绍(一)
- ABP framework - data access infrastructure (Part 2)
- Which platform is a good place to open a futures account? Is it safe to open an online futures account?
- Important knowledge of golang: atomic atomic operation
- 数组自带的方法
- Apple iPhone, Samsung mobile phone and other electronic products began to enter Russia through parallel import channels
- 《利用CAS实现自旋锁》
猜你喜欢

Ten thousand words introduction, detailed explanation of the core technical points of Tencent interview (t1-t9), and arrangement of interview questions
子级文件拖到上一级

服务器的部署及使用说明

Advanced development stage - the thickening of potential suspension wire begins A small step now, a big step next year

【无标题】激光焊接在医疗中的应用

513. Find Bottom Left Tree Value

自监督学习(SSL)Self-Supervised Learning

【TcaplusDB知识库】Tmonitor后台一键安装介绍(二)

matlab: 如何从一些数据里知道是由哪些数据相加得出一个已知数

uniapp对接腾讯即时通讯TIM 发图片消息问题
随机推荐
513. Find Bottom Left Tree Value
Glibc NPTL library pthread_ mutex_ Lock and pthread_ mutex_ Analysis of unlock
要买的理财产品年限长,划算吗?
Why can a high pass filter become a differentiator?
[tcapulusdb knowledge base] tcapulusdb tmonitor module architecture introduction
VIM backup history command
TCP协议笔记
System design and analysis - Technical Report - a solution for regularly clearing verification code
Chapitre Web 01 comprendre le développement web
HBuilderX-Light 主题能不能加个批注功能?
基金开户是有什么风险?开户安全吗
Asynclistener interface of servlet 3.0
Different implementation of CAS operation under arm and x86
云上探“店”,云商店全新升级!
If no code is moved, the project access speed drops significantly the next day. Case analysis
一文看懂经典BUCK-BOOST负电压电路
513. Find Bottom Left Tree Value
Object
Servlet 3.0的AsyncListener接口
FPGA 常用缩写及单词在工程领域内的意义