Java NIO基础与实战:如何提升IO操作性能
Java NIO 概述
Java NIO(新 I/O)是 Java 提供的一个更为高效的 I/O 处理框架。Java NIO(New I/O)是对传统 I/O(java.io)模型的改进,它引入了非阻塞 I/O 操作和面向缓冲区的数据读写方式,解决了传统 I/O 模型中的性能瓶颈。NIO 的设计目标是使 I/O 操作更加高效,特别是在大数据量、高并发情况下,能够充分利用操作系统的底层 I/O 多路复用机制。
Java NIO 的核心概念包括:Buffer(缓冲区)、Channel(通道)、Selector(选择器)。
这些组件使得 Java NIO 在处理大量并发连接时,能够减少线程的消耗,提高系统的吞吐量。
Java NIO 与传统 IO(BIO)的区别
区别维度 | BID | NIO |
---|---|---|
阻塞与非阻塞 | 传统的阻塞 I/O 模型,线程在进行 I/O 操作时会被阻塞,直到操作完成。在处理多个连接时,可能会创建大量线程,每个线程处理一个连接。这种方式的缺点是线程的开销较大,且响应速度较慢。线程数过多导致上下文切换和内存消耗大,效率低。 | Java NIO 提供了非阻塞 I/O 模型。在 NIO 中,I/O 操作不会阻塞当前线程,线程可以发起请求并继续执行其他任务。通过选择器(Selector),一个线程可以管理多个通道,从而减少了线程的数量,降低了上下文切换的成本,能够更有效地利用系统资源。 |
I/O 模 | 每个客户端连接都会占用一个线程,线程会被阻塞直到完成 I/O 操作。 | 使用 Channel 和 Buffer 进行数据传输,通过 Selector 实现单线程管理多个连接。 |
实现方式 | 通过 InputStream/OutputStream,每个线程处理一个 I/O 操作。 | 通过 Channel 和 Buffer,数据读写通过缓冲区进行,提供了非阻塞的读写方式。 |
Java NIO 的核心组件
Channel
Channel 是 NIO 中的一个接口,表示可以进行 I/O 操作的对象。Channel 可以进行读取和写入操作。
常用的 Channel 类型有:
- FileChannel:用于文件 I/O 操作。
- SocketChannel:用于 TCP 网络 I/O 操作。
- ServerSocketChannel:用于接收 TCP 客户端连接。
- DatagramChannel:用于 UDP 网络 I/O 操作。
Channel 是 IO 通讯的通道,类似于 InputStream、OutputStream,但是 Channel 是没有方向性的。
获取方式
// FileInputStream/FileOutputStream
FileInputStream fis = new FileInputStream("example.txt");
FileChannel fileInputChannel = fis.getChannel();FileOutputStream fos = new FileOutputStream("example.txt");
FileChannel fileOutputChannel = fos.getChannel();// RandomAccessFile
RandomAccessFile raf = new RandomAccessFile("example.txt", "rw");
FileChannel randomAccessFileChannel = raf.getChannel();// FileChannel
FileChannel channel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ);// Socket
Socket socket = new Socket("localhost", 8080);
SocketChannel socketChannel = socket.getChannel();// ServerSocket
ServerSocket serverSocket = new ServerSocket(8080);
ServerSocketChannel serverSocketChannel = serverSocket.getChannel();// DatagramSocket
DatagramSocket datagramSocket = new DatagramSocket(8080);
DatagramChannel datagramChannel = DatagramChannel.open(); // 需独立创建
datagramChannel.bind(datagramSocket.getLocalSocketAddress());
Buffer
NIO 中的数据传输是基于缓冲区(Buffer)的。数据读写必须先存入缓冲区,然后通过 Channel 进行传输。
Channel 读取或者写入的数据,都要写到 Buffer 中,才可以被程序操作。
Buffer 有几种类型:ByteBuffer, MappedByteBuffer, CharBuffer, IntBuffer, DoubleBuffer, LongBuffer 等。
Buffer 的主要方法:
put()
:将数据写入缓冲区。get()
:从缓冲区读取数据。flip()
:将缓冲区从写模式切换到读模式。clear()
:清空缓冲区,其实只是状态的改变,并不会真正清空。compact()
:将缓冲区中的未读数据向前移动,便于后续写操作。
因为 Channel 没有方向性,所以 Buffer 为了区分读写,引入了读模式、写模式进行区分。
写模式:新创建的 Buffer 就是写模式、调用 clear 方法清空后。
读模式:调用 flip 方法后。
获取方式
// 创建指定大小的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);// 获取字符集,假设文件使用 UTF-8 编码
Charset charset = StandardCharsets.UTF_8;// 通过字符集获取
ByteBuffer encode = charset.encode("Hello, World!");
Selector
Selector 是 NIO 的一个核心组件,允许单线程通过轮询机制来监听多个 Channel 上的事件。Selector 通过轮询的方式检查是否有可用的 I/O 操作,从而避免了每个连接都占用一个线程。
Java NIO 的开发流程
- 获取 Channel
- 创建 Buffer
- 循环的从 Channel 中获取数据,读入到 Buffer 中。进行操作:
channel.read(buffer);
buffer.flip();
//设置读模式- 循环从 buffer 中获取数据。
buffer.get();
buffer.clear();
//设置写模式
Java NIO 的工作流程
Java NIO 的工作流程可以分为以下几个步骤:
- 打开 Channel:通过
open()
方法打开相应的Channel
,如FileChannel
、SocketChannel
等。 - 配置 Buffer:创建一个
Buffer
用于读写数据,Buffer
的大小通常是固定的,写入的数据首先会被写入Buffer
中。 - 读写操作:通过
Channel
从文件或网络读取数据到Buffer
中,或者将Buffer
中的数据写入到Channel
。 - Selector 监控:在非阻塞模式下,通过
Selector
监控多个Channel
的状态。Selector
会返回一个就绪的Channel
,应用程序可以对其进行读写操作。 - 关闭 Channel:操作完成后,关闭
Channel
释放资源。
NIO 的主要优点
- 非阻塞 I/O:传统的 I/O 操作是阻塞的,线程会一直等待数据的读取或写入,而 NIO 支持非阻塞 I/O,线程可以继续执行其他任务,而无需等待 I/O 操作完成。
- 高并发:通过
Selector
,NIO 允许单个线程管理多个Channel
,大大减少了线程的开销,提高了并发处理能力。 - 高效内存管理:
Buffer
直接与内存进行交互,不像传统的 I/O 需要多次数据复制,减少了内存的消耗和处理的延迟。
示例:NIO/BIO 实现文件读取
BIO 实现
BIO(Blocking I/O)模型下,每次读取文件时,线程会被阻塞,直到完成读取操作。在传统的 BIO 中,我们通过 InputStream
来读取文件内容。下面是一个使用 BIO 方式读取文件的例子:
package fun.xuewei.nio.file;import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;/*** BIO 读取文件示例** @author 薛伟*/
public class BioFileReader {public static void main(String[] args) throws IOException {// 记录开始时间long startTime = System.nanoTime();// 使用传统的 BIO 读取文件FileInputStream fis = new FileInputStream("example.txt");BufferedReader reader = new BufferedReader(new InputStreamReader(fis));String line;while ((line = reader.readLine()) != null) {System.out.println(line); // 打印每一行}reader.close();fis.close();// 记录结束时间long endTime = System.nanoTime();System.out.println("\n\n\n");System.out.println("=============================================================");System.out.println("BIO 读取文件耗时: " + (endTime - startTime) / 1000000 + " 毫秒");System.out.println("=============================================================");}
}
在这段代码中:
- 使用
BufferedReader
从文件流中逐行读取内容,直到文件结束。 - 我们使用
System.nanoTime()
来记录开始和结束时间,以便测量执行时间。
NIO 实现
NIO 文件读取的方式使用 FileChannel
和 ByteBuffer
,能够通过非阻塞的方式高效地处理 I/O 操作。你之前提供的代码就是一个 NIO 读取文件的示例。
package fun.xuewei.nio.file;import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;/*** NIO 读取文件示例** @author 薛伟*/
public class NioFileReader {public static void main(String[] args) throws IOException {// 记录开始时间long startTime = System.nanoTime();// 打开文件通道FileInputStream fis = new FileInputStream("example.txt");FileChannel fileChannel = fis.getChannel();// 创建缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);// 获取字符集,假设文件使用 UTF-8 编码Charset charset = StandardCharsets.UTF_8;// 读取文件内容到缓冲区while (fileChannel.read(buffer) > 0) {buffer.flip(); // 切换读模式while (buffer.hasRemaining()) {// 将字节缓冲区解码为字符并打印System.out.print(charset.decode(buffer).toString());}buffer.clear(); // 清空缓冲区,准备下次读取}fileChannel.close();fis.close();// 记录结束时间long endTime = System.nanoTime();System.out.println("\n\n\n");System.out.println("=============================================================");System.out.println("NIO 读取文件耗时: " + (endTime - startTime) / 1000000 + " 毫秒");System.out.println("=============================================================");}
}
在这段代码中:
- 使用
FileChannel
和ByteBuffer
从文件中读取内容。 - 同样通过
System.nanoTime()
来记录执行时间。
测试并对比执行时间
这两段程序的差异在于文件读取的方式:
- BIO 使用传统的阻塞式读取方式,一次从文件中读取一行,适合小文件或者连接数较少的场景。
- NIO 使用
FileChannel
和ByteBuffer
,通过缓冲区和通道的组合进行读取,在处理大文件时能够更高效地读取数据。
分别运行上面两个程序可以得到下面的结果:
=============================================================
BIO 读取文件耗时: 243 毫秒
==========================================================================================================================
NIO 读取文件耗时: 59 毫秒
=============================================================
通过执行时间的比较,可以得出以下结论:
- BIO:每次读取数据时,线程会被阻塞,直到读取完数据。对于每个 I/O 操作,都需要占用一个线程进行阻塞,性能较差。
- NIO:通过缓冲区和通道的组合,能够在一个线程中高效地读取文件,并且避免了阻塞操作。在读取大文件时,NIO 的优势尤为明显,因为它可以更好地利用 CPU 和内存资源,减少线程的创建和上下文切换。
示例:NIO 实现零拷贝文件复制
在 Java NIO 中,通过利用 FileChannel
和操作系统提供的 零拷贝
(Zero-Copy)机制,可以实现高效的文件复制。零拷贝指的是在数据传输过程中,不需要将数据复制到用户空间,而是直接在内核空间进行操作,减少了内存拷贝和 CPU 的消耗。
在文件复制的场景中,使用 FileChannel.transferTo()
或 FileChannel.transferFrom()
可以实现零拷贝。这些方法直接将数据从一个通道传输到另一个通道,避免了中间缓冲区的创建和数据复制。
使用 transferTo()
方法进行零拷贝文件复制。FileChannel.transferTo()
方法允许将文件内容从一个 FileChannel
直接传输到另一个 FileChannel
,通常用于文件复制。
示例代码
import java.io.*;
import java.nio.*;
import java.nio.channels.*;public class NioFileCopyZeroCopy {public static void main(String[] args) {// 源文件路径和目标文件路径String sourceFilePath = "source.txt";String destFilePath = "destination.txt";try (FileInputStream fis = new FileInputStream(sourceFilePath);FileOutputStream fos = new FileOutputStream(destFilePath)) {// 获取源文件和目标文件的 FileChannelFileChannel sourceChannel = fis.getChannel();FileChannel destChannel = fos.getChannel();// 使用 transferTo 实现零拷贝文件复制long position = 0; // 从文件的起始位置开始复制long size = sourceChannel.size(); // 获取源文件的大小long bytesTransferred = 0;// 执行零拷贝:从源文件到目标文件while (bytesTransferred < size) {bytesTransferred += sourceChannel.transferTo(position + bytesTransferred, size - bytesTransferred, destChannel);}System.out.println("文件复制完成!");} catch (IOException e) {e.printStackTrace();}}
}
代码解析
- 打开文件流和通道:
FileInputStream
和FileOutputStream
被用来读取和写入文件。- 通过
fis.getChannel()
获取源文件的FileChannel
,通过fos.getChannel()
获取目标文件的FileChannel
。
transferTo
实现零拷贝复制:sourceChannel.transferTo(position, size, destChannel)
是FileChannel
提供的零拷贝复制方法。它会将源文件的内容从指定位置(position
)复制到目标通道destChannel
,直到复制完指定大小的数据。position
是文件的起始位置,size
是要复制的字节数。- 复制过程中,操作系统会直接在内核空间进行数据传输,减少了用户空间到内核空间的多次数据复制,从而提高了效率。
- 循环传输:
- 在实际操作中,如果文件很大,可能需要分段传输。通过循环传输数据,直到整个文件复制完成。
- 关闭资源:
- 使用
try-with-resources
语法自动关闭文件流和通道,确保资源释放。
- 使用
零拷贝机制的优势
- 性能提升:零拷贝减少了用户空间和内核空间之间的多次内存拷贝,降低了 CPU 的使用和内存消耗,特别是在传输大文件时,性能更为显著。
- 高效数据传输:零拷贝直接在操作系统内核空间进行数据传输,避免了中间缓冲区的创建和数据拷贝过程,提高了数据传输速度。
注意事项
- 文件大小:当文件非常大时,零拷贝可以大大提升性能,因为它减少了不必要的内存拷贝操作。
- 操作系统支持:零拷贝是操作系统提供的功能,确保操作系统支持零拷贝机制。在 Linux 和 Unix 系统上,通常是默认支持的。Windows 操作系统也支持
transferTo()
和transferFrom()
方法,但实现细节可能有所不同。 - 异常处理:实际使用时,注意添加适当的异常处理逻辑,确保文件流和通道的正确关闭。
示例:NIO/BIO 客户端与服务器通信
BIO 版本:客户端与服务器通信
在 BIO 模型下,每个连接都会在一个独立的线程中进行处理,线程会阻塞直到 I/O 操作完成。以下是使用 BIO 实现的客户端与服务器通信的代码。
BIO 服务器端
package fun.xuewei.nio.network;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;/*** BIO 服务器端** @author 薛伟*/
public class BioServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("BIO 服务器启动,等待连接...");while (true) {// 阻塞直到有客户端连接Socket clientSocket = serverSocket.accept();System.out.println("客户端连接:" + clientSocket.getInetAddress());// 获取输入流并读取数据BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));String message = reader.readLine(); // 阻塞直到收到消息System.out.println("收到消息:" + message);// 给客户端发送响应PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);writer.println("消息已收到");// 关闭连接clientSocket.close();}}
}
BIO 客户端
package fun.xuewei.nio.network;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;/*** BIO客户端** @author 薛伟*/
public class BioClient {public static void main(String[] args) throws IOException {Socket socket = new Socket("localhost", 8080);System.out.println("连接到服务器...");// 获取输出流并发送数据PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);writer.println("你好,服务器!");// 获取输入流并读取服务器响应BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));String response = reader.readLine();System.out.println("服务器回应: " + response);// 关闭连接socket.close();}
}
NIO 版本:客户端与服务器通信
在 NIO 模型下,我们使用 SocketChannel
和 ServerSocketChannel
来实现客户端与服务器之间的通信,并且可以通过 Selector
来管理多个连接。以下是使用 NIO 实现的客户端与服务器通信的代码。
NIO 服务器端
package fun.xuewei.nio.network;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;/*** Nio 服务器端** @author 薛伟*/
public class NioServer {public static void main(String[] args) throws IOException {// 创建 Selector 和 ServerSocketChannelSelector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);// 绑定端口serverSocketChannel.socket().bind(new InetSocketAddress(8080));// 注册到 SelectorserverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("NIO 服务器启动,等待连接...");// 获取字符集,假设文件使用 UTF-8 编码Charset charset = StandardCharsets.UTF_8;while (true) {// 等待事件发生selector.select();// 获取所有已准备就绪的 SelectionKeyIterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();// 处理接收客户端连接if (key.isAcceptable()) {ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept();clientChannel.configureBlocking(false);// 将客户端连接注册到 SelectorclientChannel.register(selector, SelectionKey.OP_READ);System.out.println("客户端连接:" + clientChannel.getRemoteAddress());}// 处理读取客户端数据if (key.isReadable()) {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(256);int bytesRead = clientChannel.read(buffer);if (bytesRead == -1) {clientChannel.close();System.out.println("客户端断开连接");} else {buffer.flip();// 将字节缓冲区解码为字符并打印String message = charset.decode(buffer).toString();System.out.println("收到消息:" + message);// 给客户端发送响应buffer.clear();String response = "消息已收到";buffer.put(response.getBytes(charset)); // 使用正确的字符集编码buffer.flip();clientChannel.write(buffer);}}}}}
}
NIO 客户端
package fun.xuewei.nio.network;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;/*** NIO 客户端** @author 薛伟*/
public class NioClient {public static void main(String[] args) throws IOException {SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 8080));// 获取字符集,假设文件使用 UTF-8 编码Charset charset = StandardCharsets.UTF_8;// 发送消息到服务器ByteBuffer buffer = ByteBuffer.allocate(256);String message = "你好,NIO 服务器!";buffer.put(message.getBytes(charset)); // 使用正确的字符集编码buffer.flip();socketChannel.write(buffer);// 接收服务器响应buffer.clear();socketChannel.read(buffer);buffer.flip();// 将字节缓冲区解码为字符并打印String response = charset.decode(buffer).toString();System.out.println("服务器回应: " + response);// 关闭 SocketChannelsocketChannel.close();}
}
总结
- 在并发请求数量较少时,BIO 和 NIO 性能差距不大。
- 随着并发请求数增多,BIO 会因为线程过多导致性能下降,而 NIO 通过事件驱动机制,能够较好地处理高并发请求。
实际场景与应用
- 高并发 Web 服务:NIO 适用于需要处理大量并发连接的场景,例如高并发的 Web 服务器、即时通讯系统、视频流服务等。
- 大文件传输:NIO 可以高效地处理大文件的读取和写入,避免了传统 I/O 中频繁的阻塞操作。
- 非阻塞网络服务:如消息队列、数据库连接池等,NIO 提供了一种高效的方式来管理网络连接。
相关文章:
Java NIO基础与实战:如何提升IO操作性能
Java NIO 概述 Java NIO(新 I/O)是 Java 提供的一个更为高效的 I/O 处理框架。Java NIO(New I/O)是对传统 I/O(java.io)模型的改进,它引入了非阻塞 I/O 操作和面向缓冲区的数据读写方式&#x…...
Elasticsearch:同义词在 RAG 中重要吗?
作者:来自 Elastic Jeffrey Rengifo 及 Toms Mura 探索 RAG 应用程序中 Elasticsearch 同义词的功能。 同义词允许我们使用具有相同含义的不同词语在文档中搜索,以确保用户无论使用什么确切的词语都能找到他们所寻找的内容。你可能会认为,由于…...
Python - Python正则表达式
正则表达式(Regular Expression),又称规则表达式。正则表达式(Regular Expression)是一组由字母和符号组成的特殊文本,用于从文本中找出满足特定格式的句子。正则表达式通常被用来检索、替换那些符合某个模…...
DeepSeek 指导手册(入门到精通)
第⼀章:准备篇(三分钟上手)1.1 三分钟创建你的 AI 伙伴1.2 认识你的 AI 控制台 第二章:基础对话篇(像交朋友⼀样学交流)2.1 有效提问的五个黄金法则2.2 新手必学魔法指令 第三章:效率飞跃篇&…...
Android adb测试常用命令大全
目录 一、查看最上层成activity名字: 二、查看Activity的任务栈: 三、获取安装包信息 四、性能相关 1、显示CPU信息 : 2、查看CPU使用信息 3、内存信息(meminfo package_name or pid 使用程序的包名或者进程id显示内存信息) 4、电量信…...
【python语言应用】最新全流程Python编程、机器学习与深度学习实践技术应用(帮助你快速了解和入门 Python)
近年来,人工智能领域的飞速发展极大地改变了各个行业的面貌。当前最新的技术动态,如大型语言模型和深度学习技术的发展,展示了深度学习和机器学习技术的强大潜力,成为推动创新和提升竞争力的关键。特别是PyTorch,凭借其…...
在不知道进程的情况下怎么关闭
在不知道具体进程ID(PID)或者进程可能会变动的情况下,关闭MinIO服务器的方法通常依赖于你如何启动MinIO以及你的操作系统环境。以下是一些建议的步骤: 1. 使用系统服务管理工具 如果你将MinIO配置为系统服务(例如在L…...
算力平台 驱动云的使用
驱动云的使用 1 进入官网注册2 上传数据3 上传模型4 创建项目5 开发环境6 停止使用 1 进入官网注册 点击这个进入 可以看到注册之后送十个算力点 如果不训练,仅仅上传数据和模型,那么也是要收费的,因为存储数据要占用驱动云的空间。 2 上…...
高校LabVIEW开发调试中的常见问题
在高校进行LabVIEW开发调试时,常常面临硬件选型不当、方案设计不合理、布线不专业以及人员流动性强等问题。这些问题可能影响项目的进展和质量。本文将总结这些问题,并给出具体的解决方案,帮助学生和团队更高效地开展开发工作。 1. 硬件选…...
数据结构——结构体位域、typedef类型重定义、宏、共用体union、枚举、虚拟内存划分
一、结构体位域 1.1 结构体位域的基础 结构体位域:把结构体字节大小扣到极致的一个类型,以bit单位 格式:struct 位域体名{数据类型 位域名:位域大小;数据类型 位域名:位域大小;...};解析:位域体名:可有可无ÿ…...
git bash删除库中的分支与文件
一、 在 GitHub 上删除非 main 分支的步骤可以分为两部分:首先在本地删除该分支,然后在 GitHub 上删除远程分支。以下是详细的步骤: 1. 删除远程分支(在 GitHub 上删除) 打开 GitHub 仓库页面,进入你的仓…...
连锁收银系统的核心架构与技术选型
在连锁门店的日常运营里,连锁收银系统扮演着极为重要的角色,它不仅承担着交易结算的基础任务,还关联着库存管理、会员服务、数据分析等多个关键环节。一套设计精良的核心架构与合理的技术选型,是保障收银系统高效、稳定运行的基础…...
称呼计算器:智能科技,简化您的计算生活
一款手机应用程序,安卓设备上使用。这款计算器应用以其简洁的界面、实用的功能和良好的用户体验而受到用户的喜爱。 计算器的主要特点包括: 基本计算功能:支持加、减、乘、除等基本运算。 科学计算器模式:提供更高级的数学运算功…...
qt的QMainWindow保存窗口和恢复窗口状态
保存窗口状态 QSettings settings("MyCompany", "MyApp"); // 指定存储的应用信息 settings.setValue("mainWindowState", saveState());saveState() 返回一个 QByteArray,包含 所有停靠窗口和工具栏的状态。QSettings 用于存储数据…...
【mysql】记一次mysql服务挂了后的数据恢复过程
现象 服务器异常,导致mysql服务异常退出,重启后,校验redo log异常 说明 mysql服务是通过docker-compose启动的,serviceName是db磁盘挂载:/var/lib/mysql挂载到本地磁盘/data/mysql 处理过程 备份 查看磁盘挂载列表 docker …...
使用 LangChain 对接硅基流动(SiliconFlow)API:构建一个智能对话系统
文章目录 什么是硅基流动(SiliconFlow)?LangChain 简介在 LangChain 中对接硅基流动步骤 1:安装必要的库步骤 2:设置 API 密钥步骤 3:编写代码代码解析步骤 4:运行代码如何扩展和改进总结 在现代…...
K8s 证书认知(K8s Certificate Awareness)
K8s 证书认知 在谈起 Kubernetes 证书时,总感觉其涵盖的内容繁多,仿佛千头万绪,让人不知该从何处着手阐述。为了更好地理清思路,本文将对相关内容进行系统的梳理和记录。 1、证书及链路关系 Kubeadm部署的集群,K8s …...
iperf
iperf 是一个网络性能测试工具,用于测量TCP和UDP的网络带宽。-c 参数表示客户端模式,用于指定要连接的服务器地址。以下是一些常见的 iperf 客户端命令示例: 基本用法 iperf -c <server_ip> <server_ip>:服务器的IP…...
【FastAPI 使用FastAPI和uvicorn来同时运行HTTP和HTTPS的Python应用程序】
在本文中,我们将介绍如何使用 FastAPI和uvicorn来同时运行HTTP和HTTPS的 Python应用程序。 简介 FastAPI是一个高性能的Web框架,可以用于构建快速、可靠的API。它基于Python的类型提示和异步支持,使得开发者可以轻松地编写出安全且高效的代…...
Windows系统安装搭建悟空crm客户管理系统 教程
1、在安装悟空 CRM 之前,需要确保你的 Windows 系统上已经安装了以下软件: Web 服务器:推荐使用 Apache 或 Nginx,这里以 Nginx 为例。你可以使用集成环境套件如 XAMPP 来简化安装过程,它包含了 Nginx 、MySQL、PHP 等…...
使用API有效率地管理Dynadot域名,清除某一文件夹中域名的默认DNS设置
关于Dynadot Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮…...
评估多智能体协作网络(MACNET)的性能:COT和AUTOGPT基线方法
评估多智能体协作网络(MACNET)的性能 方法选择:选择COT(思维链,Chain of Thought)、AUTOGPT等作为基线方法。 COT是一种通过在推理过程中生成中间推理步骤,来增强语言模型推理能力的方法,能让模型更好地处理复杂问题,比如在数学问题求解中,展示解题步骤。 AUTOGPT则是…...
(4/100)每日小游戏平台系列
新增一个点击反应速度测试! 点击反应速度测试是一款简单有趣的网页小游戏,旨在测试玩家的反应能力和专注度。通过随机高亮的颜色块,玩家需要快速点击正确的颜色,并在限定时间内挑战自己的反应速度。 📜 游戏规则 游戏开…...
Day42(补)【AI思考】-编译过程中语法分析及递归子程序分析法的系统性解析
文章目录 编译过程中语法分析及递归子程序分析法的系统性解析**一、总览:编译流程中的语法分析****1. 编译过程核心步骤** **二、语法分析的核心任务****1. 核心目标****2. 现实类比** **三、递归子程序分析法的本质****1. 方法分类****2. 递归子程序分析法的运作原…...
AcWing 190. 字串变换 --BFS-双向搜索
已知有两个字串 A, B 及一组字串变换的规则(至多 66 个规则): A1→B1 A2→B2 … 规则的含义为:在 A 中的子串 A1A1 可以变换为 B1、A2 可以变换为 B2…。 例如:A=abcd B=xyz 变换规则为: …...
visual studio导入cmake项目后打开无法删除和回车
通过Cmakelists.txt导入的项目做删除和回车无法响应,需要点击项目,然后选择配置项目就可以了...
【论文笔记】ZeroGS:扩展Spann3R+GS+pose估计
spann3r是利用dust3r做了增量式的点云重建,这里zeroGS在前者的基础上,进行了增量式的GS重建以及进行了pose的联合优化,这是一篇dust3r与GS结合的具有启发意义的工作。 abstract NeRF和3DGS是重建和渲染逼真图像的流行技术。然而,…...
Vue2中常用指令
文章目录 Vue2中常用指令1. v-text 动态渲染纯文本内容1. 作用2. 基本用法3. 示例4. 注意事项 2. v-html 动态渲染 HTML 内容1. 作用2. 基本用法3. 示例4. 注意事项 3. v-bind 动态绑定 HTML 属性1. 作用2. 基本用法3. 示例4. 注意事项5. 绑定class属性的用法6. 绑定style属性的…...
09-轮转数组
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 方法一:使用额外数组 function rotate(nums: number[], k: number): void {const n nums.length;k k % n; // 处理 k 大于数组长度的情况const newNums new A…...
本地Deepseek-r1:7b模型集成到Google网页中对话
本地Deepseek-r1:7b网页对话 基于上一篇本地部署的Deepseek-r1:7b,使用黑窗口对话不方便,现在将本地模型通过插件集成到Google浏览器中 安装Google插件 在Chrome应用商店中搜索page assis 直接添加至Chrome 修改一下语言 RAG设置本地运行的模型&#…...
算法——结合实例了解广度优先搜索(BFS)搜索
一、广度优先搜索初印象 想象一下,你身处一座陌生的城市,想要从当前位置前往某个景点,你打开手机上的地图导航软件,输入目的地后,导航软件会迅速规划出一条最短路线。这背后,就可能运用到了广度优先搜索&am…...
2025年3月营销灵感日历
2025年的第一场营销大战已经拉开帷幕了! 三月可是全年最值钱的营销黄金月——妇女节、植树节、315消费者日三大爆点连击,还有春分、睡眠日、世界诗歌日等20隐藏流量密码。 道叔连夜扒了18个行业数据,整理了这份《2025年3月营销灵感日历》&a…...
【认证授权FAQ】SSL/TLS证书过期导致的CLS认证失败
问题现象 问题分析 属于Agent操作系统的根认证机构过期问题,需要下载CA然后在系统安装。 DigiCert根证书和中间证书将在未来几年过期,一旦证书过期,基于证书颁发的SSL/TLS证书将不再信任,导致网站无法HTTPs访问。需要迁移到新的根…...
飞书专栏-TEE文档
CSDN学院课程连接:https://edu.csdn.net/course/detail/39573...
自己部署 DeepSeek 助力 Vue 开发:打造丝滑的时间线(Timeline )
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 自己…...
机器学习:集成学习和随机森林
集成学习 集成学习通过构建并合并多个模型来完成学习,从而获得比单一学习模型更显著优越的泛化能力,集成学习就是利用模型的"集体智慧",提升预测的准确率,根据单个模型方式,集成学习可分为两大类: 个体之间存在强依赖关系,其代表为Boosting算法个体之间不存在强依赖…...
力扣刷题(数组篇)
日期类 #pragma once#include <iostream> #include <assert.h> using namespace std;class Date { public:// 构造会频繁调用,所以直接放在类里面(类里面的成员函数默认为内联)Date(int year 1, int month 1, int day 1)//构…...
Jenkins 新建配置 Freestyle project 任务 六
Jenkins 新建配置 Freestyle project 任务 六 一、新建任务 在 Jenkins 界面 点击 New Item 点击 Apply 点击 Save 回到任务主界面 二、General 点击左侧 Configure Description:任务描述 勾选 Discard old builds Discard old builds:控制何时…...
5.8 软件质量与软件质量保证
文章目录 软件质量模型软件质量保证 软件质量模型 软件质量模型有ISO/IEC9126,McCall。 ISO/IEC9126从功能性、可靠性、易使用性、效率、可维护性、可移植性这6个方面对软件质量进行分析。功能性包含适合性、依从性、准确性、安全性、互用性。可靠性包含成熟性、容错…...
二次封装axios解决异步通信痛点
为了方便扩展,和增加配置的灵活性,这里将通过封装一个类来实现axios的二次封装,要实现的功能包括: 为请求传入自定义的配置,控制单次请求的不同行为在响应拦截器中对业务逻辑进行处理,根据业务约定的成功数据结构,返回业务数据对响应错误进行处理,配置显示对话框或消息形…...
Flutter项目试水
1基本介绍 本文章在构建您的第一个 Flutter 应用指导下进行实践 可作为项目实践的辅助参考资料 Flutter 是 Google 的界面工具包,用于通过单一代码库针对移动设备、Web 和桌面设备构建应用。在此 Codelab 中,您将构建以下 Flutter 应用。 该应用可以…...
Java 大视界 -- 边缘计算与 Java 大数据协同发展的前景与挑战(85)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
【第1章:深度学习概览——1.2 深度学习与机器学习、传统人工智能的区别与联系】
在科技飞速发展的时代,AI 技术如同一颗璀璨的明星,照亮了我们生活的方方面面。今天,让我们一起深入探寻 AI 技术的演进历程,看看它是如何从最初的简单规则系统,一步步发展成为如今强大的智能技术。 一、开篇故事:三杯咖啡看懂三代 AI 想象一下,你经营着一家充满温馨氛…...
游戏引擎学习第99天
仓库:https://gitee.com/mrxiao_com/2d_game_2 黑板:制作一些光场(Light Field) 当前的目标是为游戏添加光照系统,并已完成了法线映射(normal maps)的管道,但还没有创建可以供这些正常映射采样的光场。为了继续推进&…...
NixHomepage - 简单的个人网站
💻 NixHomepage - 简单的个人网站 推荐下个人的开源项目,演示网站,项目链接 https://github.com/nixgnauhcuy/NixHomepage,喜欢的话可以为我的项目点个 Star~ 📷 预览 ⚙️ 功能特性 多平台适配 明亮/暗黑模式切换 W…...
window patch按块分割矩阵
文章目录 1. excel 示意2. pytorch代码3. window mhsa 1. excel 示意 将一个三维矩阵按照window的大小进行拆分成多块2x2窗口矩阵,具体如下图所示 2. pytorch代码 pytorch源码 import torch import torch.nn as nn import torch.nn.functional as Ftorch.set_p…...
Dockerfile 详解:构建自定义镜像
Dockerfile 是一种文本文件,包含了一系列指令,用于描述如何构建一个 Docker 镜像。通过 Dockerfile,我们可以将应用程序及其所有依赖打包成镜像,确保应用在不同环境中运行时保持一致性。掌握 Dockerfile 的写法和最佳实践,能够帮助我们高效地构建和管理容器镜像。 本文将…...
vue2老版本 npm install 安装失败_安装卡主
vue2老版本 npm install 安装失败_安装卡主 特别说明:vue2老版本安装慢、运行慢,建议升级vue3element plus vite 解决方案1: 第一步、修改npm 镜像为国内镜像 使用淘宝镜像: npm config set registry https://registry.npmmir…...
【细看open_r1】精读训练和评估模型以及生成合成数据的脚本(src/open_r1)
src/open_r1 目录下主要包含了一些用于训练和评估模型以及生成合成数据的Python脚本,下面我们对其中几个主要的Python文件进行深度剖析。 configs.py 这个文件定义了两个数据类 GRPOConfig 和 SFTConfig,它们分别继承自 trl.GRPOConfig 和 trl.SFTConf…...
数据库数据恢复—MongoDB丢失_mdb_catalog.wt文件导致报错的数据恢复案例
MongoDB数据库存储模式为文档数据存储库,存储方式是将文档存储在集合之中。 MongoDB数据库是开源数据库,同时提供具有附加功能的商业版本。 MongoDB中的数据是以键值对(key-value pairs)的形式显示的。在模式设计上,数据库受到的约束更少。这…...