Java中的I/O模型——BIO、NIO、AIO
1. BIO(Blocking I/O)
1. 1 BIO(Blocking I/O)模型概述
BIO,即“阻塞I/O”(Blocking I/O),是一种同步阻塞的I/O模式。它的主要特点是,当程序发起I/O请求(比如读取数据或写入数据)时,程序会一直等到这个请求完成,才继续往下执行。在BIO模型下,每个连接都需要一个独立的线程去处理。
举个简单的例子:假设你写了一个服务器,它会接收客户端的连接,并与客户端进行数据交流。在BIO模式下,这个服务器每接收一个连接,就需要新创建一个线程来处理该连接的数据读写。这意味着:
- 如果有100个客户端同时连接服务器,服务器需要创建100个线程来处理。
- 如果客户端不发送数据,线程就会空闲等待,但依旧会占用系统资源(例如CPU和内存)。
这种模型对于连接数量较少且连接时间较短的场景比较合适。但是如果连接数量增多,比如成千上万个连接,BIO模式就显得捉襟见肘了,因为线程数量会迅速增加,系统资源会被大量占用,最终导致性能下降。
1.2BIO的工作原理
在BIO(Blocking I/O)模式中,关键的机制就是“阻塞”。简单来说,阻塞意味着当一个I/O操作(例如读取数据)在进行时,程序会“停下来”直到操作完成才能继续。让我们一步步来看一个BIO服务器的典型工作流程:
-
等待客户端连接:服务器启动后,会在某个端口上等待客户端的连接请求。
-
接收连接:当客户端发起连接时,服务器会接收该连接,并创建一个新的线程来处理这个连接。这个线程负责处理客户端发送过来的所有数据,直到连接关闭。
-
数据读取阻塞:一旦线程开始读取数据,它会进入阻塞状态,直到收到完整的数据或遇到异常。在这期间,线程不能做其他事情。想象成排队买票,一个窗口只能接待一个人,其他人都得等前一个人买完才能上前。
-
处理数据:当线程收到数据后,它会处理这些数据(例如解析请求、生成响应)。
-
发送数据阻塞:处理完数据后,线程会将响应发送给客户端。在发送过程中,线程也会被阻塞,直到数据全部发送完毕。
-
结束连接或继续等待:如果客户端断开连接,线程会关闭。如果客户端保持连接,线程会继续等待下一个数据块的到来。
整个流程看似简单,但每一个连接都占用一个线程。所以,一旦连接数较多,系统资源就会迅速消耗,产生以下问题:
1.3 BIO的优缺点分析
优点
-
逻辑简单:BIO模型结构直观,每个线程专门服务一个客户端连接,代码编写和调试相对简单。
-
适合短连接:对于连接时间较短、交互少的场景(例如Web应用中的HTTP请求),BIO模型能胜任。
缺点
-
资源占用高:由于每个连接都需要一个线程来处理,线程数量直接与连接数成正比,导致资源消耗随连接数增加而大幅度提高。
-
性能瓶颈:线程之间需要竞争CPU时间片,同时可能会导致大量线程进入等待状态(因为阻塞I/O),从而降低CPU的整体利用率。
-
扩展性差:BIO模型并不适合需要处理大量并发连接的应用场景,比如实时聊天系统或大规模服务器。因为线程数受限于系统资源,过多的线程会拖慢系统响应速度,甚至导致崩溃。
2. NIO(Non-blocking I/O)
NIO,全称非阻塞I/O(Non-blocking I/O),是Java在1.4版引入的一种新I/O模型,它通过非阻塞机制和多路复用(Selector)来管理大量的连接,目标是提高高并发下的性能。我们分步来看看NIO的特点和工作流程。
2.1 NIO的关键概念
-
非阻塞(Non-blocking):NIO允许线程在等待I/O操作时不用一直被“卡住”。比如,线程可以发起一个读取请求并立即返回,如果数据未准备好,线程可以先去做其他事,不会阻塞等待。
-
多路复用(Selector):NIO通过一个
Selector来管理多个通道(Channel)和连接。Selector是一个事件管理器,能在同一线程中监控多个连接的状态,只有当某个连接有数据准备好时才处理该连接。这使得一个线程可以处理多个连接,节省了大量的资源。
2.2 NIO的核心组件
在NIO中,有几个核心组件我们需要理解:
-
Channel(通道):类似于BIO中的“流”,但
Channel是双向的,即既能读又能写。常用的Channel包括SocketChannel(用于网络数据传输)、FileChannel(用于文件操作)等。 -
Buffer(缓冲区):在NIO中,数据读写都是通过缓冲区进行的。缓冲区是一个可以存放数据的内存区域,数据读写都会先进入缓冲区,再从缓冲区进行处理。
-
Selector(选择器):
Selector负责监听多个Channel的状态,可以在一个线程内监控多个连接,只有当Channel有数据可读、可写或有新的连接时,Selector才会触发处理。
2.3 NIO的工作流程
让我们一步步看NIO是如何工作的:
-
创建通道(Channel)并注册到选择器(Selector):
- 服务器创建一个
ServerSocketChannel并绑定端口,等待客户端连接。 ServerSocketChannel设置为非阻塞模式,并注册到Selector,表示服务器现在开始通过Selector管理该通道。
- 服务器创建一个
-
选择器轮询事件:
- 服务器主线程调用
Selector.select()方法。这是一个阻塞方法,但它会在有事件发生时返回,例如某个Channel有新数据可读、可写,或有新连接到达。 - 一旦有事件触发,
Selector会返回这些事件的集合,服务器线程可以根据这些事件选择性地处理相应的通道。
- 服务器主线程调用
-
处理事件(如读取或写入):
- 假设一个通道上有数据可读,服务器线程会读取数据并将它放入缓冲区,进行相应的业务逻辑处理。
- 读取完成后,线程可以继续检查其他通道的状态,不必在一个连接上等待。
-
结束或继续等待:
- 如果客户端关闭连接,服务器会注销该通道;否则,线程继续通过
Selector等待新事件。
- 如果客户端关闭连接,服务器会注销该通道;否则,线程继续通过
2.4 NIO的优缺点分析
优点:
-
高效的资源利用:一个线程可管理多个连接,不需要为每个连接创建一个线程,大大降低了线程的数量和资源消耗。
-
适合高并发:NIO更适合需要处理大量连接的场景,比如聊天室、实时系统等。
缺点:
-
实现复杂:NIO的代码实现比BIO复杂,理解通道、缓冲区、选择器的机制需要更多经验。
-
适用性有限:NIO适用于长连接场景(如聊天室),但对于短连接或低并发场景,BIO可能更简单易用。
2.5 NIO的应用实例——Netty
Netty 是一个基于 NIO 的高性能网络应用框架,专门为了解决 Java 网络编程中的复杂性和性能问题。Netty 封装了底层的 NIO 操作,使得编写高并发、可扩展的网络应用更加轻松。它通常用于开发高性能的网络服务器和客户端,尤其在分布式系统、微服务等需要处理大量连接的场景中非常流行。
1. Netty 的核心概念
Netty 主要使用 NIO 的非阻塞特性,并在其基础上进一步封装和优化,核心组件包括EventLoop、Channel、Pipeline 和 Handler 等。我们来详细看看这些核心部分:
-
Channel:
- Netty 中的
Channel是数据读写的基本接口,表示网络连接的抽象。不同的Channel实现支持不同协议(如 TCP、UDP),每个Channel可以绑定不同的事件。
- Netty 中的
-
EventLoop:
- Netty 使用
EventLoop来管理和调度Channel上的事件。EventLoop是一个事件循环,用于处理 I/O 操作和事件分发。通常,一个EventLoop可以管理多个Channel,从而实现高效的多路复用。
- Netty 使用
-
Pipeline 和 Handler:
Pipeline是 Netty 中的一个职责链,所有的事件和数据都会沿着这条链进行传输和处理。Handler则是Pipeline中的处理单元,每个Handler负责处理某一种类型的事件,比如读取数据、解码、业务处理等。Pipeline中的Handler可以分为“入站(Inbound)”和“出站(Outbound)”,分别用于处理输入数据和输出数据,整个数据流的处理通过Pipeline完成。
2. Netty 的工作流程
Netty 的工作流程比直接使用 NIO 更加简洁,以下是 Netty 服务器的一般流程:
-
启动引导程序:创建一个
ServerBootstrap实例,用于配置和启动服务器。ServerBootstrap允许我们设置EventLoop线程池、Channel类型以及其他参数。 -
初始化 Channel 和 Pipeline:
- 在
ServerBootstrap中配置Channel的类型(比如NioServerSocketChannel表示使用 NIO)。 - 为
Channel配置Pipeline,并将业务逻辑的Handler加入到Pipeline中,Netty 会根据事件触发不同的Handler。
- 在
-
处理连接和数据:
- 当有客户端连接到服务器时,Netty 会自动创建一个
Channel来处理该连接,并触发相应的事件。 - 数据从客户端到达后会按顺序通过
Pipeline中的每个Handler,经过编码、解码、业务处理等过程,最后将响应返回客户端。
- 当有客户端连接到服务器时,Netty 会自动创建一个
3. Netty 的优势
Netty 在底层优化了 Java NIO 的性能,同时提供了开发者友好的接口,简化了许多 NIO 编程的复杂性。
-
高并发性:Netty 的
EventLoop模型和 NIO 非阻塞特性,使得它可以高效处理大量并发连接。 -
易于扩展:Netty 的
Pipeline和Handler机制让网络应用的开发和扩展变得灵活。可以随时在Pipeline中添加、移除、替换处理逻辑。 -
丰富的功能支持:Netty 不仅支持 TCP、UDP 等常见协议,还提供了 HTTP、WebSocket 等协议的封装,方便构建多种类型的网络应用。
4. Netty 的核心组件深入分析
-
EventLoopGroup 和多线程模型:
- Netty 的
EventLoopGroup是一种线程管理机制,它的作用是管理EventLoop,并负责调度所有的 I/O 事件和任务。通常,一个EventLoopGroup会分配多个线程,每个线程负责管理一个或多个Channel,从而实现高效的并发处理。 - 通常在服务端会使用两个
EventLoopGroup,一个用于接收新连接(Boss Group),另一个用于处理数据读写(Worker Group)。这使得 Netty 能够分离连接建立与数据处理的任务,避免资源争用。
- Netty 的
-
Channel 和 ChannelFuture:
Channel作为 I/O 操作的核心接口,支持异步操作。每个操作都会返回一个ChannelFuture对象,用于监听操作的完成状态,比如连接是否成功、数据是否发送完毕等。ChannelFuture提供回调机制,允许我们在操作完成后触发相应的处理逻辑。这种异步操作方式让 Netty 能够更高效地进行并发处理。
-
ChannelHandler 和 Pipeline:
ChannelHandler是 Netty 的处理单元,用于对 I/O 事件进行处理。通过Pipeline,可以将多个Handler组成一个处理链条。Pipeline会根据事件类型(比如读取、写入)将事件依次传递给链条中的Handler。Pipeline中的Handler分为入站和出站两种,入站Handler负责处理从客户端来的请求数据,而出站Handler则处理响应数据。这样可以实现数据的灵活处理和清晰的逻辑分离。
-
ByteBuf 缓冲区:
- Netty 提供了
ByteBuf作为数据缓冲区替代NIO的ByteBuffer。ByteBuf的功能更丰富,比如动态扩展、读写指针分离等,极大地简化了数据处理过程。
- Netty 提供了
5. Netty 常见的使用场景
Netty 的高性能和灵活性使它在许多应用场景中表现出色,以下是一些常见的场景:
-
实时聊天系统:
- 由于聊天系统需要支持大量长连接,且需要实时响应消息,Netty 的高并发处理能力非常适合这种场景。通过
Pipeline可以实现数据的快速传递和处理,保证消息的快速响应。
- 由于聊天系统需要支持大量长连接,且需要实时响应消息,Netty 的高并发处理能力非常适合这种场景。通过
-
微服务间通信:
- 在微服务架构中,服务之间的通信通常是通过网络完成的。Netty 支持多种协议,并能够封装成适合服务间通信的自定义协议(例如基于 TCP 的协议)。Netty 的高效 I/O 模型可以减少通信延迟,适合服务间的大量数据传输。
-
游戏服务器:
- 在线游戏需要支持大量玩家的连接,同时对实时性要求高。Netty 可以用于游戏服务器的底层网络架构,利用 NIO 模型减少连接管理的资源消耗,并提供快速响应。
-
分布式系统中作为 RPC 框架:
- Netty 是许多 RPC 框架的底层通信支持。比如
Dubbo、gRPC等分布式系统中常用的框架都使用 Netty 来处理底层网络通信。通过 Netty,能够实现低延迟的远程调用。
- Netty 是许多 RPC 框架的底层通信支持。比如
6. Netty 示例:构建一个简单的 Echo 服务器
为了加深理解,我们来看一个 Netty 示例:一个简单的 Echo 服务器。Echo 服务器会将客户端发送的数据原封不动地返回给客户端。
public class EchoServer {public static void main(String[] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 用于接收连接EventLoopGroup workerGroup = new NioEventLoopGroup(); // 用于处理数据try {ServerBootstrap b = new ServerBootstrap(); // 创建引导程序b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 使用NIO.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new EchoServerHandler()); // 加入Echo处理器}});ChannelFuture f = b.bind(8080).sync(); // 绑定端口并启动f.channel().closeFuture().sync(); // 等待关闭} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ctx.write(msg); // 写回收到的数据ctx.flush(); // 立即发送}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close(); // 发生异常时关闭通道}
}
这个代码展示了 Netty 的基本工作流程:
ServerBootstrap设置服务器的基本配置。EventLoopGroup负责处理连接和数据。ChannelInitializer配置了Pipeline,将处理器加入到处理链中。EchoServerHandler在channelRead中接收数据并返回给客户端。
3. AIO(Asynchronous I/O)
AIO 模型是在 Java 7 中引入的,也被称为 NIO.2,它与 BIO 和 NIO 的关键不同点在于完全异步的处理方式。AIO 允许我们在 I/O 操作完成后自动调用回调函数,不需要通过轮询或等待的方式来检查 I/O 是否已完成,这种特性在处理长时间的、数据密集型的任务时特别有优势。
3.1 AIO 的关键特性
-
异步非阻塞:
- 在 AIO 模型中,操作是非阻塞且异步的。无论是连接、读取还是写入操作,都会直接返回,通过回调机制在操作完成后通知应用进行相应的处理。线程无需等待数据读写完成,能够更高效地处理其他任务。
-
基于回调的编程方式:
- AIO 通过回调机制实现异步处理。每当 I/O 操作完成后,系统会自动调用指定的回调方法,这样线程无需手动轮询操作状态。回调机制使得程序结构更加简洁,减少了阻塞等待和轮询操作。
3.2 AIO 的核心组件
在 AIO 中,核心组件围绕 AsynchronousChannel 系列接口设计,这些接口提供了异步 I/O 的主要操作。
-
AsynchronousServerSocketChannel:
- 用于异步地处理服务器端的连接请求。它类似于 NIO 中的
ServerSocketChannel,但它提供了异步的 accept 操作,支持在新连接到达时自动触发回调。
- 用于异步地处理服务器端的连接请求。它类似于 NIO 中的
-
AsynchronousSocketChannel:
- 用于客户端或服务器端进行异步数据传输的通道。
AsynchronousSocketChannel提供了异步的读写操作,操作完成后会触发回调。
- 用于客户端或服务器端进行异步数据传输的通道。
-
CompletionHandler:
- 这是 AIO 处理中最重要的接口之一。
CompletionHandler负责定义回调逻辑,在 I/O 操作完成或失败后会自动调用。CompletionHandler接口包含两个方法:completed:在 I/O 操作成功时调用,处理成功逻辑。failed:在 I/O 操作失败时调用,处理异常逻辑。
- 这是 AIO 处理中最重要的接口之一。
3.3 AIO 的工作流程
AIO 的工作流程基于回调,我们可以用步骤来概述其操作:
-
建立连接:
- 使用
AsynchronousServerSocketChannel监听客户端连接,通过accept方法注册一个回调CompletionHandler。当有新的连接请求时,回调函数会被触发,服务器会获取该连接的AsynchronousSocketChannel进行后续的处理。
- 使用
-
异步读取:
- 在服务器获取到客户端连接的
AsynchronousSocketChannel后,可以调用read方法进行数据读取。此方法也是异步的,接收一个CompletionHandler作为参数,数据读取完成后将自动触发回调处理。
- 在服务器获取到客户端连接的
-
异步写入:
- 数据处理完毕后,可以调用
write方法将结果返回给客户端,同样也是异步的。写入完成后会触发相应的回调,保证了数据的准确发送。
- 数据处理完毕后,可以调用
3.4 AIO 的优缺点
优点:
- 完全异步:AIO 的回调机制减少了阻塞等待,提高了程序的响应速度。
- 资源节约:不需要多线程来管理 I/O,可以在较少线程下完成高并发的 I/O 操作,特别适合高并发的长连接场景。
缺点:
- 复杂性增加:AIO 的回调编程方式需要设计异步流程,逻辑上会比传统的同步代码复杂。
- 适用场景有限:AIO 适用于高并发、长时间保持连接的应用场景(如文件传输服务器),但在短连接或低并发情况下不具备明显优势。
3.5 AIO 示例:构建一个简单的 Echo 服务器
以下是一个使用 AIO 的简单 Echo 服务器示例。该服务器会异步接收客户端的数据并返回。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;public class AioEchoServer {public static void main(String[] args) throws IOException {AsynchronousServerSocketChannel serverChannel =AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080));System.out.println("AIO Echo Server is listening on port 8080...");// 接收客户端连接serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel clientChannel, Void attachment) {// 继续接收其他连接serverChannel.accept(null, this);// 读取客户端数据ByteBuffer buffer = ByteBuffer.allocate(1024);clientChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {attachment.flip();clientChannel.write(attachment, attachment, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {attachment.clear();clientChannel.read(attachment, attachment, this);}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {exc.printStackTrace();try {clientChannel.close();} catch (IOException e) {e.printStackTrace();}}});}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {exc.printStackTrace();try {clientChannel.close();} catch (IOException e) {e.printStackTrace();}}});}@Overridepublic void failed(Throwable exc, Void attachment) {exc.printStackTrace();}});// 阻止主线程退出try {Thread.currentThread().join();} catch (InterruptedException e) {e.printStackTrace();}}
}
总结
- BIO:每个连接一个线程,适用于低并发、小规模应用。
- NIO:多路复用、非阻塞,适合高并发场景。
- AIO:完全异步,回调机制适合高并发、长连接场景。
相关文章:
Java中的I/O模型——BIO、NIO、AIO
1. BIO(Blocking I/O) 1. 1 BIO(Blocking I/O)模型概述 BIO,即“阻塞I/O”(Blocking I/O),是一种同步阻塞的I/O模式。它的主要特点是,当程序发起I/O请求(比如…...
【软考知识】敏捷开发与统一建模过程(RUP)
敏捷开发模式 概述敏捷开发的主要特点包括:敏捷开发的常见实践包括:敏捷开发的优势:敏捷开发的挑战:敏捷开发的方法论: ScrumScrum 的核心概念Scrum 的执行过程Scrum 的适用场景 极限编程(XP)核…...
Redis常见面试题(二)
Redis性能优化 Redis性能测试 阿里Redis性能优化 使用批量操作减少网络传输 Redis命令执行步骤:1、发送命令;2、命令排队;3、命令执行;4、返回结果。其中 1 与 4 消耗时间 --> Round Trip Time(RTT,…...
业务模块部署
一、部署前端 1.1 window部署 下载业务模块前端包。 (此包为耐威迪公司发布,请联系耐威迪客服或售后获得) 包名为:业务-xxxx-business (注:xxxx为发布版本号) 此文件部署位置为:……...
【LeetCode】【算法】48. 旋转图像
LeetCode 48. 旋转图像 题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 思路 思路:再次拜见K神…...
【STM32F1】——9轴姿态模块JY901与串口通信(上)
【STM32F1】——9轴姿态模块JY901与串口通信(上) 一、简介 本篇主要对调试JY901模块的过程进行总结,实现了以下功能。 串口普通收发:使用STM32F103C8T6的USART2实现9轴姿态模块JY901串口数据的读取,并利用USART1发送到串口助手。 串口DMA收发:使用STM32F103C8T6的USART…...
Docker网络概述
1. Docker 网络概述 1.1 网络组件 Docker网络的核心组件包括网络驱动程序、网络、容器以及IP地址管理(IPAM)。这些组件共同工作,为容器提供网络连接和通信能力。 网络驱动程序:Docker支持多种网络驱动程序,每种驱动程…...
Vite与Vue Cli的区别与详解
它们的功能非常相似,都是提供基本项目脚手架和开发服务器的构建工具。 主要区别 Vite在开发环境下基于浏览器原生ES6 Modules提供功能支持,在生产环境下基于Rollup打包; Vue Cli不区分环境,都是基于Webpack。 在生产环境下&…...
深究JS底层原理
一、JS中八种数据类型判断方法 在JavaScript中,数据类型分为两大类:基本(原始)数据类型和引用(对象)数据类型。 基本数据类型(Primitive Data Types) 基本数据类型是表示简单的数…...
数据分析-41-时间序列预测之机器学习方法XGBoost
文章目录 1 时间序列1.1 时间序列特点1.1.1 原始信号1.1.2 趋势1.1.3 季节性和周期性1.1.4 噪声1.2 时间序列预测方法1.2.1 统计方法1.2.2 机器学习方法1.2.3 深度学习方法2 XGBoost2.1 模拟数据2.2 生成滞后特征2.3 切分训练集和测试集2.4 封装专用格式2.5 模型训练和预测3 参…...
json转java对象 1.文件读取为String 2.String转为JSONObject 3.JSONObject转为Class
一.参考王广帅的 服务器起服时的加载 private void readConfigFile(String configDir, Class<?> clazz) throws Exception {String fileName getConfigFileName(clazz);File configFile new File(configDir, fileName);// 读取所有的行,因此,应…...
基于卷积神经网络的农作物病虫害识别系统(pytorch框架,python源码)
更多图像分类、图像识别、目标检测等项目可从主页查看 功能演示: 基于卷积神经网络的农作物病虫害检测(pytorch框架)_哔哩哔哩_bilibili (一)简介 基于卷积神经网络的农作物病虫害识别系统是在pytorch框架下实现的…...
ETLCloud异常问题分析ai功能
在数据处理和集成的过程中,异常问题的发生往往会对业务运营造成显著影响。为了提高ETL(提取、转换、加载)流程的稳定性与效率,ETLCloud推出了智能异常问题分析AI功能。这一创新工具旨在实时监测数据流动中的潜在异常,自…...
【1】 Kafka快速入门-从原理到实践
文章目录 🔍 一、引言📜 二、Kafka 的历史🏗️ 三、Kafka 的核心结构🖥️ (一)Broker📋 (二)Topic📄 (三)Partition📤 (四)Producer📥 (五)Consumer🐒 (六)Zookeeper💡 四、Kafka 的重点概念📨 (一)消息📏 (二)偏移量(Offset)🔄 (…...
go语言中的map类型详解
在Go语言中,map是一种内建的数据结构,提供了键值对(key-value)的存储方式。map通常用于实现快速的查找和关联数组,适合在需要根据键来高效查找值的场景下使用。 基本概念 map是一个无序的集合,它存储了键…...
GBase 8a MPP Cluster V9安装部署
GBase 8a MPP Cluster V9安装部署 安装环境准备 节点角色操作系统地址配置GBASE版本gbase01.gbase.cnGCWARE,COOR,DATACentOS 7.9192.168.20.1422C4GGBase 8a MPP Cluster V9 9.5.3.28.12gbase02.gbase.cnGCWARE,COOR,DATACentOS 7.9192.168.20.1432C4GGBase 8a MPP Cluster …...
静态库、动态库、framework、xcframework、use_frameworks!的作用、关联核心SDK工程和测试(主)工程、设备CPU架构
1.1库的概念 库:程序代码的集合,编译好的二进制文件加上头文件供使用,共享程序代码的一种方式。 1.2库的分类 根据开源情况分为:开源库(能看到具体实现)、闭源库(只公开调用的的接口…...
C++ | Leetcode C++题解之第552题学生出勤记录II
题目: 题解: class Solution { public:static constexpr int MOD 1000000007;vector<vector<long>> pow(vector<vector<long>> mat, int n) {vector<vector<long>> ret {{1, 0, 0, 0, 0, 0}};while (n > 0) {…...
网站架构知识之Ansible(day020)
1.Ansible架构 Inventory 主机清单:被管理主机的ip列表,分类 ad-hoc模式: 命令行批量管理(使用ans模块),临时任务 playbook 剧本模式: 类似于把操作写出脚本,可以重复运行这个脚本 2.修改配置 配置文件:/etc/ansible/ansible.cfg 修改配置文件关闭主机Host_key…...
K8s使用nfs
改动点 ip和路径改为自己的 --- apiVersion: v1 kind: ServiceAccount metadata:name: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: nfs-client --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata:nam…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
Android Framework预装traceroute执行文件到system/bin下
文章目录 Android SDK中寻找traceroute代码内置traceroute到SDK中traceroute参数说明-I 参数(使用 ICMP Echo 请求)-T 参数(使用 TCP SYN 包) 相关文章 Android SDK中寻找traceroute代码 设备使用的是Android 11,在/s…...
前端打包工具简单介绍
前端打包工具简单介绍 一、Webpack 架构与插件机制 1. Webpack 架构核心组成 Entry(入口) 指定应用的起点文件,比如 src/index.js。 Module(模块) Webpack 把项目当作模块图,模块可以是 JS、CSS、图片等…...
使用python进行图像处理—图像变换(6)
图像变换是指改变图像的几何形状或空间位置的操作。常见的几何变换包括平移、旋转、缩放、剪切(shear)以及更复杂的仿射变换和透视变换。这些变换在图像配准、图像校正、创建特效等场景中非常有用。 6.1仿射变换(Affine Transformation) 仿射变换是一种…...
多模态学习路线(2)——DL基础系列
目录 前言 一、归一化 1. Layer Normalization (LN) 2. Batch Normalization (BN) 3. Instance Normalization (IN) 4. Group Normalization (GN) 5. Root Mean Square Normalization(RMSNorm) 二、激活函数 1. Sigmoid激活函数(二分类&…...
【动态规划】B4336 [中山市赛 2023] 永别|普及+
B4336 [中山市赛 2023] 永别 题目描述 你做了一个梦,梦里有一个字符串,这个字符串无论正着读还是倒着读都是一样的,例如: a b c b a \tt abcba abcba 就符合这个条件。 但是你醒来时不记得梦中的字符串是什么,只记得…...
八、【ESP32开发全栈指南:UDP客户端】
1. 环境准备 安装ESP-IDF v4.4 (官方指南)确保Python 3.7 和Git已安装 2. 创建项目 idf.py create-project udp_client cd udp_client3. 完整优化代码 (main/main.c) #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h&…...
