阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一锅端
1 阻塞跟非阻塞1.1 阻塞阻塞IO阻塞IO情况下当用户调用read后用户线程会被阻塞等内核数据准备好并且数据从内核缓冲区拷贝到用户态缓存区后read才会返回。可以看到是阻塞的两个部分。CPU把数据从磁盘读到内核缓冲区。CPU把数据从内核缓冲区拷贝到用户缓冲区。1.2 非阻塞非阻塞IO非阻塞IO发出read请求后发现数据没准备好会继续往下执行此时应用程序会不断轮询polling内核询问数据是否准备好当数据没有准备好时内核立即返回EWOULDBLOCK错误。直到数据被拷贝到应用程序缓冲区read请求才获取到结果。并且你要注意这里最后一次 read 调用获取数据的过程是一个同步的过程是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。1.3 IO多路复用IO多路复用非阻塞情况下无可用数据时应用程序每次轮询内核看数据是否准备好了也耗费CPU能否不让它轮询当内核缓冲区数据准备好了以事件通知当机制告知应用进程数据准备好了呢应用进程在没有收到数据准备好的事件通知信号时可以忙写其他的工作。此时IO多路复用就派上用场了。IO多路复用中文比较让人头大IO多路复用的原文叫 I/O multiplexing这里的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态来同时管理多个I/O流. 发明它的目的是尽量多的提高服务器的吞吐能力。实现一个线程监控多个IO请求哪个IO有请求就把数据从内核拷贝到进程缓冲区拷贝期间是阻塞的现在已经可以通过采用mmap地址映射的方法达到内存共享效果避免真复制提高效率。IO多路复用像select、poll、epoll都是I/O多路复用的具体的实现。1.3.1 selectselect是第一版IO复用提出后暴漏了很多问题。select 会修改传入的参数数组这个对于一个需要调用很多次的函数是非常不友好的。select 如果任何一个sock(I/O stream)出现了数据select 仅仅会返回但不会告诉是那个sock上有数据只能自己遍历查找。select 只能监视1024个链接。select 不是线程安全的如果你把一个sock加入到select, 然后突然另外一个线程发现这个sock不用要收回这个select 不支持的。1.3.2pollpoll 修复了 select 的很多问题。poll 去掉了1024个链接的限制。poll 从设计上来说不再修改传入数组。但是poll仍然不是线程安全的 这就意味着不管服务器有多强悍你也只能在一个线程里面处理一组 I/O 流。你当然可以拿多进程来配合了不过然后你就有了多进程的各种问题。1.3.3 epollepoll 可以说是 I/O 多路复用最新的一个实现epoll 修复了poll 和select绝大部分问题 比如epoll 现在是线程安全的。epoll 现在不仅告诉你sock组里面数据还会告诉你具体哪个sock有数据你不用自己去找了。epoll 内核态管理了各种IO文件描述符 以前用户态发送所有文件描述符到内核态然后内核态负责筛选返回可用数组现在epoll模式下所有文件描述符在内核态有存查询时不用传文件描述符进去了。1.3.4 三者对比对比图横轴 Dead connections 是链接数的意思叫这个名字只是它的测试工具叫deadcon。纵轴是每秒处理请求的数量可看到epoll每秒处理请求的数量基本不会随着链接变多而下降的。poll 和/dev/poll 就很惨了。但 epoll 有个致命的缺点是只有linux支持。比如平常Nginx为何可以支持4W的QPS是因为它会使用目标平台上面最高效的I/O多路复用模型。1.4 异步IO异步IO然后你会发现上面的提到过的操作都不是真正的异步因为两个阶段总要等待会儿而真正的异步 I/O 是内核数据准备好和数据从内核态拷贝到用户态这两个过程都不用等待。很庆幸Linux给我们准备了aio_read跟aio_write函数实现真实的异步当用户发起aio_read请求后就会自动返回。内核会自动将数据从内核缓冲区拷贝到用户进程空间应用进程啥都不用管。2 同步跟异步2.1 同步同步跟异步的区别在于数据从内核空间拷贝到用户空间是否由用户线程完成这里又分为同步阻塞跟同步非阻塞两种。同步阻塞此时一个线程维护一个连接该线程完成数据到读写跟处理到全部过程数据读写时时线程是被阻塞的。同步非阻塞非阻塞的意思是用户线程发出读请求后读请求不会阻塞当前用户线程不过用户线程还是要不断的去主动判断数据是否准备OK了。此时还是会阻塞等待内核复制数据到用户进程。他与同步BIO区别是使用一个连接全程等待我们以同步非阻塞为例如下可看到在将数据从内核拷贝到用户空间这一过程是由用户线程阻塞完成的。同步非阻塞2.2 异步对于异步来说用户进行读或者写后将立刻返回由内核去完成数据读取以及拷贝工作完成后通知用户并执行回调函数用户提供的callback此时数据已从内核拷贝到用户空间用户线程只需要对数据进行处理即可不需要关注读写用户不需要等待内核对数据的复制操作用户在得到通知时数据已经被复制到用户空间。我们以如下的真实异步非阻塞为例。异步IO可发现用户在调用之后会立即返回由内核完成数据的拷贝工作并通知用户线程进行回调。2.3 同步跟异步对比同步关注的消息通信机制synchronous communication在发出一个调用时在没有得到结果之前该调用就不返回。但是一旦调用返回就得到返回值了。换句话说就是由调用者主动等待这个调用的结果。异步关注消息通信机制asynchronous communication调用在发出之后这个调用就直接返回了所以没有返回结果。换句话说当一个异步过程调用发出后调用者不会立刻得到结果。而是在调用发出后被调用者通过状态、通知来通知调用者或通过回调函数处理这个调用。3 Java IO在Java中我们使用socket进行网络通信IO主要有三种模式主要看内核支持哪些。BIO同步阻塞IO。NIO同步非阻塞IO。AIO异步非阻塞IO。3.1 BIO同步阻塞IO每个客户端的Socket连接请求服务端都会对应有个处理线程与之对应对于没有分配到处理线程的连接就会被阻塞或者拒绝。相当于是一个连接一个线程。BIOBIO特点使用一个独立的线程维护一个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同步非阻塞IO之NIO服务器端保存一个Socket连接列表然后对这个列表进行轮询如果发现某个Socket端口上有数据可读时说明读就绪则调用该socket连接的相应读操作。如果发现某个 Socket端口上有数据可写时说明写就绪则调用该socket连接的相应写操作。如果某个端口的Socket连接已经中断则调用相应的析构方法关闭该端口。这样能充分利用服务器资源效率得到了很大提高在进行IO操作请求时候再用个线程去处理是一个请求一个线程。Java中使用Selector、Channel、Buffer来实现上述效果。NIO每个线程中包含一个Selector对象它相当于一个通道管理器可以实现在一个线程中处理多个通道的目的减少线程的创建数量。远程连接对应一个channel数据的读写通过buffer均在同一个channel中完成并且数据的读写是非阻塞的。通道创建后需要注册在selector中同时需要为该通道注册感兴趣事件客户端连接服务端事件、服务端接收客户端连接事件、读事件、写事件selector线程需要采用轮训的方式调用selector的select函数直到所有注册通道中有兴趣的事件发生则返回否则一直阻塞。而后循环处理所有就绪的感兴趣事件。以上步骤解决BIO的两个瓶颈不必对每个连接分别创建线程。数据读写非阻塞。下面对以下三个概念做一个简单介绍Java NIO由以下三个核心部分组成selectorSelector 允许单线程处理多个Channel。如果你的应用打开了多个连接通道但每个连接的流量都很低使用Selector就会很方便。要使用Selector得向Selector注册Channel然后调用他的select方法这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回线程就可以处理这些事件事件的例子入有新连接接进来数据接收等。Channel基本上所有的IO在NIO中都从一个Channel开始。Channel有点像流数据可以从channel读到buffer也可以从buffer写到channel。Buffer缓冲区本质上是一个可以读写数据的内存块可以理解成是一个容器对象(含数组)该对象提供了一组方法可以更轻松的使用内存块缓冲区对象内置了一些机制能够跟踪和记录缓冲区的状态变换情况Channel提供从文件网络读取数据的渠道但是读取或者写入的数据都必须经由Buffer。channel和buffer有好几种类型。下面是Java NIO中的一些主要channel的实现FileChannel DatagramChannel SocketChannel ServerSocketChannel正如你所看到的这些通道涵盖了UDP和TCP网络IO以及文件IO。以下是Java NIO里关键的buffer实现ByteBuffer CharBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer在微服务阶段一个请求可能涉及到多个不同服务之间的跨服务器调用如果你想实现高性能的PRC框架来进行数据传输那就可以基于Java NIO做个支持长连接、自定义协议、高并发的框架比如Netty。Netty本身就是一个基于NIO的网络框架 封装了Java NIO那些复杂的底层细节给你提供简单好用的抽象概念来编程。比如Dubbo底层就是用的Netty。Netty通讯模式3.3 AIOAIO是异步非阻塞IO相比NIO更进一步进程读取数据时只负责发送跟接收指令数据的准备工作完全由操作系统来处理。

相关新闻

红黑树硬核讲解

红黑树硬核讲解

1 引言 预防针&#xff1a;红黑树本来就是基本算法中的难点&#xff0c;所以看此文时建议先有点预备心理或知识铺垫&#xff0c;没接触过RBT而直接看此文的话&#xff0c;绝对懵逼。 为了数据的查询跟增删方便&#xff0c;系统引入了二叉查找树&#xff0c;它具有左节点 <…

2026/7/8 7:24:02 阅读更多 →
PyTorch-2.x镜像功能详解,为什么它适合通用开发

PyTorch-2.x镜像功能详解,为什么它适合通用开发

PyTorch-2.x镜像功能详解&#xff0c;为什么它适合通用开发 你是否经历过这样的场景&#xff1a;刚配好一个深度学习环境&#xff0c;运行几行代码就报错“ModuleNotFoundError”&#xff1b;想快速验证一个新想法&#xff0c;却卡在CUDA版本不匹配上&#xff1b;团队协作时&a…

2026/7/3 19:00:00 阅读更多 →
用Qwen-Image-Layered做了个广告图,效果超出预期

用Qwen-Image-Layered做了个广告图,效果超出预期

用Qwen-Image-Layered做了个广告图&#xff0c;效果超出预期 你有没有过这样的经历&#xff1a;客户临时要求把一张已定稿的电商主图里“限时5折”改成“限时3折”&#xff0c;还要保持文字阴影、字体粗细和背景融合度完全一致&#xff1f;改完发现背景色偏了一点&#xff0c;…

2026/7/6 18:09:23 阅读更多 →

最新新闻

Jetson远程开发最佳实践:Cursor替代VS Code的架构优势与ARM64适配指南

Jetson远程开发最佳实践:Cursor替代VS Code的架构优势与ARM64适配指南

1. 为什么Jetson开发者现在必须用Cursor替代VS Code做远程开发Jetson系列设备——从Nano、Xavier NX到Orin AGX——本质上是一台嵌入式Linux工作站&#xff0c;但它的物理形态和资源限制决定了它无法像x86笔记本那样直接运行完整IDE。我最早在2021年用Jetson Nano跑YOLOv3时&am…

2026/7/11 1:51:19 阅读更多 →
基于Dify + Ollama的AI辅助小说创作工作台搭建完全指南

基于Dify + Ollama的AI辅助小说创作工作台搭建完全指南

基于Dify + Ollama的AI辅助小说创作工作台搭建完全指南 前言 在长篇网文创作领域,AI辅助写作正在从“玩具”走向“工具”。传统的对话式AI(如直接与ChatGPT对话生成内容)存在几个致命问题:缺乏对作者既有作品风格的理解、无法维护长篇小说庞大的人物和世界观设定、生成内…

2026/7/11 1:51:19 阅读更多 →
Linux 的 I2C、SPI、Regmap 子系统

Linux 的 I2C、SPI、Regmap 子系统

I2C 子系统断言1. I2C 需要 “平台总线” 作为"引子"是因为它没有硬件枚举能力&#xff0c;必须通过静态配置知道总线上有什么设备。USB/PCI 有硬件枚举&#xff0c;所以不需要这个中间层&#xff08;除了控制器本身&#xff09;。整个链路的枚举和诞生过程是这样的&…

2026/7/11 1:51:19 阅读更多 →
MATLAB App Designer R2024a 实战:3步将现有脚本封装为带界面应用

MATLAB App Designer R2024a 实战:3步将现有脚本封装为带界面应用

MATLAB App Designer R2024a 实战&#xff1a;3步将现有脚本封装为带界面应用每次看到自己精心编写的MATLAB脚本只能通过命令行运行&#xff0c;总觉得少了点什么。那些复杂的参数输入、需要反复修改的变量、以及只有自己才能看懂的运行流程&#xff0c;都在提醒我&#xff1a;…

2026/7/11 1:49:19 阅读更多 →
GBFR Logs终极指南:简单快速的碧蓝幻想Relink伤害统计工具

GBFR Logs终极指南:简单快速的碧蓝幻想Relink伤害统计工具

GBFR Logs终极指南&#xff1a;简单快速的碧蓝幻想Relink伤害统计工具 【免费下载链接】gbfr-logs GBFR Logs lets you track damage statistics with a nice overlay DPS meter for Granblue Fantasy: Relink. 项目地址: https://gitcode.com/gh_mirrors/gb/gbfr-logs …

2026/7/11 1:49:19 阅读更多 →
电气隔离技术与TLP241A光耦在工业系统中的应用

电气隔离技术与TLP241A光耦在工业系统中的应用

1. 为什么电气隔离对现代电子系统至关重要 在工业自动化、医疗设备和新能源系统中&#xff0c;电气隔离早已从"可有可无"变成了"生死攸关"的设计要素。去年我参与调试的一套光伏逆变器系统就遭遇过惨痛教训——由于控制板与功率板之间缺乏有效隔离&#xf…

2026/7/11 1:47:18 阅读更多 →

日新闻

5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南

5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南

5分钟完全掌握&#xff1a;ComfyUI ControlNet预处理器终极使用指南 【免费下载链接】comfyui_controlnet_aux ComfyUIs ControlNet Auxiliary Preprocessors 项目地址: https://gitcode.com/gh_mirrors/co/comfyui_controlnet_aux 想要让AI图像生成真正听从你的指挥吗&…

2026/7/11 0:02:12 阅读更多 →
PIC18F45K42驱动EPT-14A4005P压电蜂鸣器方案详解

PIC18F45K42驱动EPT-14A4005P压电蜂鸣器方案详解

1. 项目背景与核心需求 在工业控制、安防系统和智能家居等领域&#xff0c;可靠的声音警报系统是不可或缺的基础组件。传统蜂鸣器存在音量不足、音质模糊等问题&#xff0c;而基于压电陶瓷技术的EPT-14A4005P蜂鸣器配合PIC18F45K42微控制器&#xff0c;能够构建一套适应性强、音…

2026/7/11 0:04:12 阅读更多 →
大模型推理中的算子融合优化:LayerNorm + Attention 的 CUDA Kernel 手写与验证

大模型推理中的算子融合优化:LayerNorm + Attention 的 CUDA Kernel 手写与验证

大模型推理中的算子融合优化&#xff1a;LayerNorm Attention 的 CUDA Kernel 手写与验证 一、GPU 利用率 30%&#xff1a;分开的算子吃掉所有带宽 推理服务的 GPU 利用率监测显示一个反直觉的现象&#xff1a;计算核心&#xff08;SM&#xff09;利用率不到 30%&#xff0c;但…

2026/7/11 0:04:12 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools&#xff1a;5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱&#xff0c;支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/10 19:03:29 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里&#xff0c;参与了关于混合后量子密码学的讨论&#xff0c;应付端点攻击找茬的人&#xff0c;还参与留言板讨论后&#xff0c;发现“威胁模型”对多数人仍是陌生概念&#xff0c;且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/9 13:46:46 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”&#xff1a;我理解的渗透测试到底是什么&#xff1f;每次看到新闻里说某个大公司的数据被“黑”了&#xff0c;或者某个网站被攻击导致服务瘫痪&#xff0c;你是不是和我一样&#xff0c;心里会冒出两个念头&#xff1a;一是“这黑客真厉害”&#x…

2026/7/9 21:41:05 阅读更多 →

月新闻