Java详解I/O
前言:
小弟能力不足,认知有限,难免考虑不全面,希望大佬能给出更好的建议,指出存在的问题和不足,在此跪谢。
IO发展史
Java中对于I/O能力的支持主要分为三个比较关键的阶段:
BIO
第一个阶段是起步阶段JDK1.0 ~ JDK1.3,这个阶段JDK是处于BIO阶段的,也就是同步阻塞模式,该阶段的类库还非常的初级,对系统层面的一些网络编程的API都没有进行实现,因此这个阶段的很多大型应用服务器都采用C或者C++语言来进行开发的,因为C或者C++可以直接调用操作系统提供的非阻塞I/O能力;
NIO
第二个阶段从JDK1.4开始的,从JDK1.4开始,Java新增了java.nio的包,正式支持的NIO,提供了许多非阻塞I/O开发的API和类库;
AIO
第三个阶段是从JDK1.7开始的,这一次是对原来的NIO类库进行了升级,官方称为NIO 2.0,该版本不但强化了原来的基于I/O多路复用模型的NIO模式,同时新增了异步的AIO功能,所以也有很多人称之为AIO。
各个IO介绍
BIO
在Java中,BIO(Blocking I/O)指的是阻塞式I/O,是一种基本的I/O模型。它的实现原理相对简单,但在高并发场景下性能较差。下面我将详细介绍BIO的实现原理。
-
阻塞式I/O:
在BIO中,当一个线程在进行I/O操作时,如果数据没有准备好,该线程会被阻塞,直到数据准备好并被读取或写入。这意味着一个线程只能处理一个连接,如果有大量连接同时到来,就需要大量线程来处理,这会导致资源消耗过大。 -
实现原理:
- 服务端:服务端通过ServerSocket监听客户端的连接请求。当有连接请求到来时,服务端会创建一个新的线程来处理该连接。
- 客户端:客户端通过Socket向服务端发起连接请求。一旦连接建立,客户端和服务端之间可以进行数据的读取和写入。
-
服务端示例代码:
思路:在服务端的代码中,我们创建了一个固定大小的线程池,用于处理客户端的连接请求。每当有客户端连接时,就会将连接交给线程池中的一个线程来处理,这样可以提高并发处理能力。同时,我们定义了一个
ClientHandler
类来处理客户端的请求,这样可以更好地组织代码逻辑。这样的设计可以更好地满足企业级生产环境的要求,提高了系统的并发处理能力和稳定性。当然你还可以加入日志打印,更好的排查问题,但是因为这种已经过时,所以只是简单示例。
import java.io.*; import java.net.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class Server {public static void main(String[] args) {ServerSocket serverSocket = null;ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个固定大小的线程池try {serverSocket = new ServerSocket(8080);System.out.println("Server started. Waiting for client...");while (true) {// 等待客户端连接Socket clientSocket = serverSocket.accept();System.out.println("Client connected: " + clientSocket.getRemoteSocketAddress());// 使用线程池处理客户端请求executor.execute(new ClientHandler(clientSocket));}} catch (IOException e) {e.printStackTrace();} finally {try {if (serverSocket != null) {serverSocket.close();}executor.shutdown(); // 关闭线程池} catch (IOException e) {e.printStackTrace();}}}private static class ClientHandler implements Runnable {private Socket clientSocket;public ClientHandler(Socket clientSocket) {this.clientSocket = clientSocket;}@Overridepublic void run() {try {// 获取输入流BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));// 获取输出流PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);// 读取客户端发送的数据String clientMessage = input.readLine();System.out.println("Received from client: " + clientMessage);// 向客户端发送数据output.println("Hello, client!");// 关闭流和连接input.close();output.close();clientSocket.close();} catch (IOException e) {e.printStackTrace();}}} }
-
客户端实例代码实现:
import java.io.*; import java.net.*;public class Client {public static void main(String[] args) {Socket socket = null;try {socket = new Socket("localhost", 8080);System.out.println("Connected to server.");// 获取输入流BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 获取输出流PrintWriter output = new PrintWriter(socket.getOutputStream(), true);// 向服务端发送数据output.println("Hello, server!");// 读取服务端发送的数据String serverMessage = input.readLine();System.out.println("Received from server: " + serverMessage);// 关闭流和连接input.close();output.close();socket.close();} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}} }
-
适用场景:
BIO适用于连接数较少且吞吐量要求不高的场景,例如传统的Socket通信应用。 -
局限性:
由于BIO的阻塞特性,它在高并发场景下表现较差,因为大量线程会因为I/O阻塞而处于等待状态,导致资源浪费。
总的来说,BIO是一种简单直观的I/O模型,但在高并发场景下存在性能瓶颈。随着业务的发展,通常会选择更高效的NIO(Non-blocking I/O)或者AIO(Asynchronous I/O)来替代BIO。
NIO
在Java中,NIO(New I/O)是一种非阻塞I/O模型,相比于传统的BIO(Blocking I/O),NIO具有更高的并发处理能力。下面我将详细介绍NIO的实现原理。
-
非阻塞I/O:
NIO的核心是非阻塞I/O,它允许一个线程处理多个连接,当一个连接上的I/O操作不可立即完成时,线程可以去处理其他连接,而不是被阻塞。 -
核心组件:
- 通道(Channel):用于读取和写入数据,可以是文件、套接字等。
- 缓冲区(Buffer):用于临时存储数据,读取数据到缓冲区或将缓冲区中的数据写入通道。
- 选择器(Selector):用于监听多个通道的事件,例如连接就绪、读就绪、写就绪等。
-
实现原理:
- 服务端:服务端通过ServerSocketChannel监听连接请求,一旦有连接到来,会将该连接注册到Selector上,并监听连接就绪事件。
- 客户端:客户端通过SocketChannel向服务端发起连接请求,连接建立后也会注册到Selector上。
-
NIO服务器端示例代码:
实现思路:在以下代码中,我们引入了日志打印服务,使用了Java自带的Logger类来记录日志。同时,我们使用了线程池来处理客户端的连接请求和数据读写操作,以提高并发处理能力。对于各种可能遇到的问题,比如连接超时、网络异常、数据读写异常等,我们在相应的位置进行了异常处理,并记录了相应的日志,以便于排查和解决问题。
这样的设计更加符合企业级生产规范,提高了系统的并发处理能力和稳定性,并且对各种异常情况进行了处理,使得系统更加健壮可靠。
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger;public class NIOServer {private static final Logger logger = Logger.getLogger(NIOServer.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {Selector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();keyIterator.remove();if (key.isAcceptable()) {executor.execute(() -> handleAccept(key, selector));} else if (key.isReadable()) {executor.execute(() -> handleRead(key));}}}} catch (IOException e) {logger.severe("Error in NIO server: " + e.getMessage());}}private static void handleAccept(SelectionKey key, Selector selector) {try {ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverSocketChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(selector, SelectionKey.OP_READ);} catch (IOException e) {logger.severe("Error in handleAccept: " + e.getMessage());}}private static void handleRead(SelectionKey key) {try {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = clientChannel.read(buffer);if (bytesRead == -1) {clientChannel.close();key.cancel();} else if (bytesRead > 0) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from client: " + new String(data));// 可以在这里处理接收到的数据}} catch (IOException e) {logger.severe("Error in handleRead: " + e.getMessage());}} }
-
NIO客户端的代码:
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger;public class NIOClient {private static final Logger logger = Logger.getLogger(NIOClient.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {SocketChannel socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress("localhost", 8080));while (!socketChannel.finishConnect()) {// 等待连接完成}executor.execute(() -> {try {String message = "Hello, server!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());socketChannel.write(buffer);buffer.clear();int bytesRead = socketChannel.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from server: " + new String(data));// 可以在这里处理接收到的数据}} catch (IOException e) {logger.severe("Error in NIO client: " + e.getMessage());} finally {try {socketChannel.close();} catch (IOException e) {logger.severe("Error in closing socket channel: " + e.getMessage());}}});} catch (IOException e) {logger.severe("Error in NIO client: " + e.getMessage());}} }
-
适用场景:
NIO适用于高并发的网络应用,例如Web服务器、聊天服务器等,能够更高效地处理大量连接。
总的来说,NIO通过Selector、Channel和Buffer的组合,实现了非阻塞I/O,提高了系统的并发处理能力。然而,NIO编程相对复杂,需要处理事件的就绪状态,因此在实际应用中通常会使用NIO框架或者基于NIO的高级框架,如Netty。
AIO
在Java中,AIO(Asynchronous I/O)是一种基于事件和回调机制的I/O模型,相比于传统的BIO(Blocking I/O)和NIO(Non-blocking I/O),AIO更加适用于处理大量并发连接。下面我将详细介绍AIO的实现原理。
-
异步I/O:
AIO的核心是异步I/O,它允许一个线程在等待数据就绪的同时继续做其他事情,当数据就绪后通过回调机制来处理数据。这种模型相比于NIO更加灵活,因为不需要手动检查就绪状态,而是通过事件通知来处理。 -
核心组件:
- 异步通道(AsynchronousChannel):用于进行异步I/O操作,包括文件和套接字等。
- 异步操作结果(AsynchronousResult):用于存储异步操作的结果,可以通过回调方式获取结果。
- 异步处理器(AsynchronousHandler):用于处理异步操作完成后的回调。
-
实现原理:
- 服务端:服务端通过AsynchronousServerSocketChannel监听连接请求,一旦有连接到来,会调用accept方法,并通过回调方式处理连接就绪事件。
- 客户端:客户端通过AsynchronousSocketChannel向服务端发起连接请求,连接建立后也可以通过回调方式处理后续的读写操作。
-
简单的AIO服务器示例代码:
实现思路:针对企业级生产环境中高可用的通信需求,以下是一个更完善的AIO服务端和客户端的Java代码。该代码考虑了各种可能遇到的问题,并给出了切实可行的异常解决方案。同时,引入了日志打印服务,使用了Java自带的Logger类来记录日志,并使用了线程池来处理客户端的连接请求和数据读写操作,以提高并发处理能力。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; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Logger;public class AIOServer {private static final Logger logger = Logger.getLogger(AIOServer.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel clientChannel, Void attachment) {serverSocketChannel.accept(null, this); // 接受下一个连接executor.execute(() -> handleRead(clientChannel));}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in accepting connection: " + exc.getMessage());}});// 阻止主线程退出Thread.currentThread().join();} catch (IOException | InterruptedException e) {logger.severe("Error in AIO server: " + e.getMessage());}}private static void handleRead(AsynchronousSocketChannel clientChannel) {ByteBuffer buffer = ByteBuffer.allocate(1024);clientChannel.read(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {if (bytesRead == -1) {try {clientChannel.close();} catch (IOException e) {logger.severe("Error in closing client channel: " + e.getMessage());}return;}buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from client: " + new String(data));// 可以在这里处理接收到的数据buffer.clear();clientChannel.read(buffer, null, this); // 继续读取数据}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in reading from client: " + exc.getMessage());}});} }
-
简单的AIO客户端示例代码:
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger;public class AIOClient {private static final Logger logger = Logger.getLogger(AIOClient.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 8080), null, new CompletionHandler<Void, Void>() {@Overridepublic void completed(Void result, Void attachment) {String message = "Hello, server!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());socketChannel.write(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesWritten, Void attachment) {if (buffer.hasRemaining()) {socketChannel.write(buffer, null, this); // 继续写入数据} else {buffer.clear();socketChannel.read(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from server: " + new String(data));// 可以在这里处理接收到的数据}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in reading from server: " + exc.getMessage());}});}}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in writing to server: " + exc.getMessage());}});}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in connecting to server: " + exc.getMessage());}});// 阻止主线程退出Thread.currentThread().join();} catch (IOException | InterruptedException e) {logger.severe("Error in AIO client: " + e.getMessage());}} }
-
适用场景:
AIO适用于需要处理大量并发连接且对性能要求较高的场景,例如高性能的网络服务器、金融交易系统等。
总的来说,AIO通过异步I/O和事件回调机制,实现了高效的并发处理能力,相比于NIO更加灵活和高效。然而,AIO在Java中的实现相对较新,需要较高的技术要求,因此在实际应用中通常会使用成熟的AIO框架或者基于AIO的高级框架。
在Java中,有一些成熟的AIO框架或者基于AIO的高级框架,它们提供了更加便捷和高效的异步I/O编程方式。以下是一些常用的框架:
-
Netty:
Netty是一个基于NIO的高性能网络通信框架,但它也提供了对AIO的支持。Netty的异步事件驱动模型和高度可定制的架构使得它成为构建高性能、可扩展的网络应用程序的理想选择。Netty提供了丰富的功能,包括TCP/UDP传输、HTTP编解码、WebSocket支持等,广泛应用于网络服务器、分布式系统等领域。 -
Grizzly:
Grizzly是一个基于NIO的高性能网络框架,它提供了对AIO的支持,并且具有高度可扩展性和灵活性。Grizzly可以用于构建高性能的Web服务器、应用服务器等网络应用。 -
Apache MINA:
Apache MINA是一个基于NIO的网络应用框架,它提供了对AIO的支持,并且具有良好的扩展性和灵活性。MINA可以用于构建各种类型的网络应用,包括游戏服务器、即时通讯服务器等。
这些框架都提供了对AIO的封装和抽象,简化了异步I/O编程的复杂性,同时提供了丰富的功能和高性能的网络通信能力。在实际应用中,选择合适的框架取决于具体的需求和项目背景,但无论选择哪个框架,都可以极大地简化异步I/O编程的复杂性,提高开发效率和系统性能。
相关文章:
Java详解I/O
前言: 小弟能力不足,认知有限,难免考虑不全面,希望大佬能给出更好的建议,指出存在的问题和不足,在此跪谢。 IO发展史 Java中对于I/O能力的支持主要分为三个比较关键的阶段: BIO 第一个阶段…...
数据处理生产环境_spark获取df列当前日期的前一天日期
需求描述: 我现在有一个dataframe,名为dfin,样例数据如下 a1_id_lxha2_PHtime比亚迪_汉1232023-11-15 12:12:23比亚迪_汉1252023-11-15 13:14:51比亚迪_汉1232023-11-15 12:13:23比亚迪_汉1262023-11-16 14:12:34比亚迪_秦2312023-11-15 14:12:28比亚迪_秦2342023…...

第四代智能井盖传感器,实时守护井盖位安全
城市管理中井盖的安全问题始终是一个不容忽视的方面。传统的巡检方式不仅效率低下,无法实现实时监测,而且很难准确掌握井盖的异动状态。因此智能井盖传感器的应用具有重要意义。这种智能传感器可以帮助政府实时掌握井盖的状态,一旦发现异常情…...
【前端知识】Node——文件流的读写操作
四种基本流类型: 1.Writable: 可以向其写入数据的流 2.Readable: 可以从中读取数据的流 3.Duplex:同时为Readable 和 Writable 4.Transform: Duplex可以在写入和读取数据时修改或转换数据的流 一、Readable const fs require(fs);// 创建文件的Readable const rea…...

解决证书加密问题:OpenSSL与urllib3的兼容性与优化
在使用客户端证书进行加密通信时,用户可能会遇到一些问题。特别是当客户端证书被加密并需要密码保护时,OpenSSL会要求用户输入密码。这对于包含多个调用的大型会话来说并不方便,因为密码无法在连接的多个调用之间进行缓存和重复使用。用户希望…...
#gStore-weekly | gAnswer源码解析 调用NE模块流程
简介 gAnswer系统的主要思想,是将自然语言问题转化为语义查询图,再和RDF图做子图匹配。在转换成查询图的第一步就是确定查询图的节点,即节点提取(Node Extraction, NE)。 查询图中的节点由实体(entity&am…...

vscode 配置 lua
https://luabinaries.sourceforge.net/ 官网链接 主要分为4个步骤 下载压缩包,然后解压配置系统环境变量配置vscode的插件测试 这里你可以选择用户变量或者系统环境变量都行。 不推荐空格的原因是 再配置插件的时候含空格的路径 会出错,原因是空格会断…...

vscode设置代码模板
一键生成vue3模板代码 效果演示 输入vue3 显示快捷键 按回车键 一键生成自定义模板 实现方法 进入用户代码片段设置 选择片段语言 vue.json输入自定义的代码片段 prefix是触发的内容,按自己的喜好来就行; body是模板代码,写入自己需要的…...

用css实现原生form中radio单选框和input的hover已经focus的样式
一.问题描述:用css实现原生form中radio单选框和input的hover已经focus的样式 在实际的开发中,一般公司ui都会给效果图,比如单选按钮radio样式,input输入框hover的时候样式,以及focus的时候样式,等等&#…...
uniapp:录音权限检查,录音功能
1.可以使用:plus.navigator.checkPermission检查运行环境的权限 2.如果是"undetermined"表示程序未确定是否可使用此权限,此时调用对应的API时系统会弹出提示框让用户确认:plus.audio.getRecorder() <template><view cla…...

Rust开发——切片(slice)类型
1、什么是切片 在 Rust 中,切片(slice)是一种基本类型和序列类型。在 Rust 官方文档中,切片被定义为“对连续序列的动态大小视图”。 但在rust的Github 源码中切片被定义如下: 切片是对一块内存的视图,表…...

如何给shopify motion主题的产品系列添加description
一、Description是什么 Description是一种HTML标签类型,通过指定Description的内容,可以帮助搜索引擎以及用户更好的理解当前网页包含的主要了内容。 二、Description有什么作用 1、基本作用,对于网站和网页做一个简单的说明。 2、吸引点击&…...

力扣刷题-二叉树-二叉树最小深度
给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。(注意题意) 示例 1: 输入:root [3,9,20,null,null,15,7] 输出&#x…...

注解方式优雅的实现 Redisson 分布式锁
1前言 日常开发中,难免遇到一些并发的场景,为了保证接口执行的一致性,通常采用加锁的方式,因为服务是分布式部署模式,本地锁Reentrantlock和Synchnorized这些就先放到一边了,Redis的setnx锁存在无法抱保证…...

PHP/Laravel通过经纬度计算距离获取附近商家
实际开发中,常常需要获取用户附近的商家,思路是 获取用户位置(经纬度信息)在数据库中查询在距离范围内的商家 注: 本文章内计算距离所使用地球半径统一为 6378.138 km public function mpa_list($latitude,$longitude,$distance){// $latitude 34.306465;// $longitude 10…...

grafana面板介绍
grafana 快速使用 背景 随着公司业务的不断发展,紧接来的是业务种类的增加、服务器数量的增长、网络环境的越发复杂以及发布更加频繁,从而不可避免地带来了线上事故的增多,因此需要对服务器到应用的全方位监控,提前预警…...
实验三 循环结构程序设计(Python)
第1关:打印图形 zm=input("") #代码开始#代码结束def print_pattern(letter):if not letter.isalpha() or not letter.isupper():print("请输入大写字母")returnstart_char = Aend_char = letterfor i in range(ord(start_char), ord(end_char) + 1):spa…...
Flutter笔记:目录与文件存储以及在Flutter中的使用(上)
Flutter笔记 目录与文件存储以及在Flutter中的使用(上) 文件系统基础知识与路径操作 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:h…...
注意了!申请流量卡时地址一定不要填写学校,不好下卡哦!
当我们在网上购买流量卡时,都会要求让填写准确的收货地址,但是对于收货地址你填对了吗? 很多朋友在提交流量卡申请之后,往往会被运营商拒审,对于拒审的原因除了比较常见的信息填写有有误、涉及禁发地区、重复申…...
minio使用shell上传文件
minio使用shell上传文件 前言1. 编写调用脚本2.测试脚本上传3.候选脚本 前言 业务场景需要实现,服务器文件上传至存储服务。一种方式是安装minio的linux客户端,另一种方式是通过调用minio的api接口实现文件上传。后一种方式不需要依赖minio的客户端使用…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...