为什么android要使用Binder机制
1.linux中大多数标准 IPC 场景(如管道、消息队列、ioctl 等)的进程间通信机制
+------------------+ +------------------+ +------------------+
| 用户进程 A | | 内核空间 | | 用户进程 B |
| (User Space A) | | (Kernel Space) | | (User Space B) |
+------------------+ +------------------+ +------------------+| | || 1. copy_from_user() | ||----------------------------> || | || | || | 2. copy_to_user() || | -------------------------->|| | |
📝 图解说明:
-
用户进程 A 将数据从用户空间拷贝到内核空间:
- 使用
copy_from_user()
函数。 - 此操作将数据从用户缓冲区复制到内核缓冲区。
- 使用
-
内核保存数据:
- 数据暂时存储在内核中的某个缓冲区(如驱动私有缓冲区、socket 缓冲区等)。
-
用户进程 B 从内核空间读取数据:
- 使用
copy_to_user()
函数。 - 此操作将数据从内核缓冲区复制到用户进程 B 的缓冲区。
- 使用
✅ 总结:
- 发生了 单向通信两次数据复制(物理内存拷贝)(用户 → 内核 → 用户)。
- 虽然性能不如共享内存等零拷贝机制,但适用于大多数标准 IPC 场景(如管道、消息队列、ioctl 等)。
缺点: 物理内存拷贝(Physical Memory Copy)是指在不同内存区域之间实际复制数据内容,而不是通过指针映射或页表共享来访问同一块内存。它对系统性能、资源利用率和程序响应性都有直接影响。
🧠 物理内存拷贝会影响哪些方面?
影响维度 | 描述 |
---|---|
性能 | 拷贝大量数据会消耗 CPU 时间,影响整体执行效率。 |
延迟 | 数据拷贝耗时会导致操作延迟,特别是在实时系统中影响用户体验。 |
吞吐量 | 频繁的内存拷贝会降低系统的并发处理能力。 |
内存带宽 | 大量拷贝占用内存总线带宽,可能成为瓶颈。 |
能耗 | 在移动设备上,频繁拷贝会增加功耗,影响电池寿命。 |
物理内存拷贝会影响性能、延迟、内存带宽和能耗,尤其是在大数据传输或高频率调用场景下尤为明显。
推荐做法:
- 小数据量通信:可以接受一定拷贝开销,使用标准 IPC(如 Binder、Pipe)即可。
- 大数据量通信:优先考虑 共享内存、mmap、MemoryFile、ashmem 等零拷贝方案。
- 实时性要求高:避免使用同步阻塞 IPC,推荐异步 + 零拷贝机制。
2.Binder机制
不同进程通信时,只有在客户端拿到代理类调用方法的时候,才是Binder进行用户空间和内核空间数据传输的过程!!!
步骤 | 操作描述 | 技术细节(以数据发送为例) |
---|---|---|
步骤 1 | Binder 驱动准备 | 为进程通信做准备,实现“内存映射(mmap)”,创建接收缓存区、映射关系(内核缓存区 ↔ Server 用户空间) |
步骤 2 | Client 发送数据 | Client 进程通过系统调用 copy_from_user ,将数据从“用户空间”拷贝到“内核缓存区”,再由 Binder 驱动通知 Server 进程 |
步骤 3 | Server 处理请求 | Server 进程被 Binder 驱动唤醒后,从内核缓存区读取数据、解析,调用目标方法处理 |
步骤 4 | Server 返回结果 | Server 进程通过 copy_to_user ,将处理结果从内核缓存区拷贝到 Client 进程的用户空间,Binder 驱动通知 Client 进程 |
三、优点总结
- 传输效率高:数据拷贝次数少(仅 1 - 2 次 ),依托内存映射让“用户空间 ↔ 内核空间”直接共享数据,减少冗余操作。
- 灵活适配:为接收进程动态分配“接收缓存区”,无需提前固定大小,适配不同数据量的通信场景。
(客户端发送数据:客户端通过 transact() 方法发送数据时,只需将数据写入 Parcel 并传递给 Binder 驱动,无需提前声明数据长度。
服务端接收缓存区创建:Binder 驱动根据客户端实际发送的数据量,为服务端进程动态分配足够大小的内核缓存区(通过 mmap 映射到用户空间),用于接收数据。 ) - 死亡通知机制
// 客户端注册死亡通知
mRemote.linkToDeath(new DeathRecipient() {@Overridepublic void binderDied() {// 服务进程崩溃后的回调}
});
实现原理:驱动检测到服务进程退出时,发送 BR_DEAD_BINDER 消息给所有客户端。
3.代码举例
代码中的1-4是代码执行流程!!!!
以下是一个完整的 AIDL 跨进程通信示例,包含服务端和客户端的 Java 代码,实现简单的加法运算功能:
一、服务端代码
1. 创建 AIDL 文件
在 Android 项目的 main
目录下,新建 aidl
文件夹(与 java
目录同级 ),然后创建包名对应的目录(如 com/example/aidlserver
),在该目录下新建 IMyAidlInterface.aidl
文件:
// IMyAidlInterface.aidl
package com.example.aidlserver;interface IMyAidlInterface {int add(int num1, int num2);
}
2. 编写 Service 类
创建 IRemoteService.java
,继承 Service
,实现 AIDL 接口的 Stub
:
package com.example.aidlserver;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;public class IRemoteService extends Service {private static final String TAG = "IRemoteService";2.实现 AIDL生成的Stub 类(Stub是服务端Binder实现)private IBinder iBinder = new IMyAidlInterface.Stub() {@Overridepublic int add(int num1, int num2) throws RemoteException {return num1 + num2;}};3.接受客户端发来的bind请求,返回服务端Binder@Overridepublic IBinder onBind(Intent intent) {return iBinder;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "服务已启动");return super.onStartCommand(intent, flags, startId);}
}
3. 注册 Service 到清单文件
在 AndroidManifest.xml
中声明 Service
,设置可被其他进程访问:
<serviceandroid:name=".IRemoteService"android:exported="true"><intent-filter><action android:name="com.example.aidlserver.IRemoteService" /></intent-filter>
</service>
二、客户端代码
1. 复制 AIDL 文件
将服务端的 IMyAidlInterface.aidl
文件,完整复制到客户端项目的 aidl
目录(同样保持包名路径 com/example/aidlserver
)。
2. 编写 Activity 类
创建 MainActivity.java
,绑定服务端 Service
并调用 AIDL 方法:
package com.example.aidlclient;import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity;import com.example.aidlserver.IMyAidlInterface;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private IMyAidlInterface aidlInterface;private TextView resultTv;private IBinder mRemote; // 保存服务端 Binder 引用private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {4.服务绑定后,根据传过来的service获取服务端Binder的代理对象!!!// 将 IBinder 转换为 AIDL 接口aidlInterface = IMyAidlInterface.Stub.asInterface(service);// 2. 保存 Binder 引用,用于注册死亡通知mRemote = service;// 3. 注册 Binder 死亡通知(关键步骤)try {mRemote.linkToDeath(deathRecipient, 0);} catch (RemoteException e) {e.printStackTrace();}Log.d(TAG, "服务已连接");}@Overridepublic void onServiceDisconnected(ComponentName name) {aidlInterface = null;Log.d(TAG, "服务已断开");}};// 死亡通知回调实现private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {@Overridepublic void binderDied() {// 服务端进程崩溃时的处理逻辑runOnUiThread(() -> {Toast.makeText(MainActivity.this, "服务已崩溃", Toast.LENGTH_SHORT).show();// 重置引用,可选择重新绑定服务if (mRemote != null) {mRemote.unlinkToDeath(this, 0);mRemote = null;}aidlInterface = null;// 可添加自动重连逻辑bindService(...);});}};性能开销:频繁注册 / 解除死亡通知会有一定开销,建议在应用生命周期内合理管理。public void binderDied() {// 重新绑定服务bindService(new Intent(MainActivity.this, IRemoteService.class),serviceConnection, BIND_AUTO_CREATE);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);resultTv = findViewById(R.id.result_tv);Button bindBtn = findViewById(R.id.bind_btn);Button callBtn = findViewById(R.id.call_btn);// 绑定服务bindBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();// 设置服务端包名和 Service actionintent.setPackage("com.example.aidlserver");intent.setAction("com.example.aidlserver.IRemoteService");1.绑定服务bindService(intent, serviceConnection, BIND_AUTO_CREATE);}});// 调用 AIDL 方法callBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (aidlInterface != null) {try {int result = aidlInterface.add(5, 3);resultTv.setText("计算结果:" + result);} catch (RemoteException e) {e.printStackTrace();}} else {resultTv.setText("服务未连接");}}});}@Overrideprotected void onDestroy() {super.onDestroy();// 解绑服务unbindService(serviceConnection);}
}
具体流程拆解
一、流程拆解 + 代码对应(结合之前 AIDL 示例)
1. 客户端 bindService
客户端通过 bindService
发起绑定服务的请求,代码如下(以客户端 MainActivity
为例):
Intent intent = new Intent();
intent.setPackage("com.example.aidlserver"); // 服务端包名
intent.setAction("com.example.aidlserver.IRemoteService"); // 服务端 Service 的 action
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
- 作用:通过隐式意图,找到服务端对应的
Service
,发起绑定,触发服务端onBind
执行。
2. 服务端 onBind
返回 IBinder
服务端 IRemoteService
中,onBind
返回 AIDL 生成的 Stub
(本质是 IBinder
实现类 ):
public class IRemoteService extends Service {private IBinder iBinder = new IMyAidlInterface.Stub() { // Stub 实现了 IBinder@Overridepublic int add(int num1, int num2) throws RemoteException {return num1 + num2;}};@Overridepublic IBinder onBind(Intent intent) {return iBinder; // 返回 IBinder 实例}
}
- 说明:
Stub
是 AIDL 工具根据.aidl
文件自动生成的类,它继承Binder
并实现 AIDL 接口,用于跨进程通信时的 “桥梁”。
3. 客户端 onServiceConnected
回调
客户端通过 ServiceConnection
的 onServiceConnected
拿到服务端返回的 IBinder
,代码:
private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 把 IBinder 转成 AIDL 接口代理aidlInterface = IMyAidlInterface.Stub.asInterface(service); }@Overridepublic void onServiceDisconnected(ComponentName name) {aidlInterface = null;}
};
重点:!!!!
一、asInterface(service) 的工作原理
1. 服务端返回的 service 参数
服务绑定成功后,服务端通过 onBind() 返回的 IBinder 对象(即 Stub 实例)
会被传递到客户端的 onServiceConnected() 回调中,作为 service 参数。
2. asInterface() 方法的源码逻辑
AIDL 自动生成的 Stub.asInterface() 方法大致如下:public static IMyAidlInterface asInterface(android.os.IBinder obj) {if (obj == null) {return null;}// 检查是否在同一进程(关键判断)android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (iin != null && iin instanceof IMyAidlInterface) {return (IMyAidlInterface) iin; // 同一进程:直接返回服务端的 Stub 本身}// 跨进程:创建并返回代理对象 Proxyreturn new IMyAidlInterface.Stub.Proxy(obj);
}同一进程(客户端和服务端在同一个 APK 中):
obj.queryLocalInterface() 返回服务端的 Stub 实例(因为 Stub 实现了 IInterface),
此时客户端直接拿到服务端的 Binder 对象,方法调用等效于本地调用。跨进程(客户端和服务端是不同 APK):
queryLocalInterface() 返回 null,此时创建 Proxy 对象,
它封装了底层的 Binder 通信逻辑
(将方法调用转为 transact() 请求,才开始进行数据复制那些内核态空间的操作),
让客户端通过代理间接访问服务端。二、为什么需要代理对象?
1. 跨进程通信的复杂性
客户端和服务端在不同进程,无法直接调用对方的方法。
代理对象(Proxy)的作用是:
将客户端的方法调用(如 add(5, 3))转换为 Binder 协议的 transact() 请求;
将参数打包为 Parcel 并发送给服务端;
接收服务端返回的结果并解包。2. 对开发者透明的封装
通过 asInterface() 返回代理对象,AIDL 隐藏了底层的跨进程通信细节,
让开发者感觉就像在调用本地对象的方法一样简单。
4. 客户端通过代理类调用接口!!!!!!!!!!!!!!
触发 Binder 驱动的实际数据传输和跨进程交互!!!!!!!
拿到 aidlInterface
(代理对象)后,直接调用 AIDL 定义的方法,比如:
try {int result = aidlInterface.add(5, 3); // 调用远程服务的 add 方法resultTv.setText("计算结果:" + result);
} catch (RemoteException e) {e.printStackTrace();
}
一、add(5, 3)
调用触发的完整流程
1. 客户端代理对象(Proxy
)处理调用
当执行 aidlInterface.add(5, 3)
时,实际调用的是 Stub.Proxy
类的 add()
方法(AIDL 自动生成):
// Proxy 类的 add 方法(伪代码)
@Override
public int add(int num1, int num2) throws RemoteException {// 1. 创建 Parcel 用于打包参数Parcel _data = Parcel.obtain();Parcel _reply = Parcel.obtain();int _result;try {// 2. 将参数写入 Parcel(用户空间)_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(num1);_data.writeInt(num2);3. 通过 Binder 发送请求到服务端(关键跨进程操作)!!!!!!!!!!!!!mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);// 4. 从返回结果中读取数据(用户空间)_reply.readException();_result = _reply.readInt();} finally {_reply.recycle();_data.recycle();}return _result;
}
2. Binder 驱动的数据复制与映射
- 步骤 3 的
transact()
触发内核操作:- 客户端用户空间 → 内核空间:
Binder 驱动将_data
中的数据(5
和3
)从客户端进程的用户空间复制到内核缓存区(第一次内存拷贝)。 - 内核空间 → 服务端用户空间:
通过内存映射(mmap),服务端进程的用户空间直接与内核缓存区共享同一块物理内存,无需再次复制(零拷贝)。 - 服务端处理请求:
服务端的Stub
在onTransact()
中解析参数,调用真正的add()
方法计算结果(5 + 3 = 8
)。 - 结果返回:
结果(8
)从服务端用户空间写入内核缓存区(通过映射直接操作),再由 Binder 驱动复制到客户端的用户空间(第二次内存拷贝)。
- 客户端用户空间 → 内核空间:
3、Binder 高效性的核心
- 零拷贝优化:
通过内存映射(mmap),服务端可直接访问内核缓存区的数据,避免了传统 IPC(如 Socket)的多次拷贝(用户空间 → 内核空间 → 用户空间)。 - 两次拷贝(双向的,单项就只有一次拷贝):
Binder 实际只需要两次拷贝(客户端用户空间 → 内核空间 → 客户端用户空间),是 Android 中最高效的 IPC 机制之一。
而服务绑定(bindService()
)只是为这个过程建立通信通道,并不涉及实际业务数据的传输。
二、补充说明(帮你更深入理解)
- 同进程 vs 跨进程:如果客户端和服务端在同一个进程(比如调试时),
Stub.asInterface
会直接返回服务端的Stub
本身,不走跨进程通信逻辑(相当于本地接口调用);跨进程时才会返回Proxy
代理。 - 异常处理:跨进程调用可能因服务端崩溃、连接断开等抛
RemoteException
,所以客户端调用接口时要捕获异常,做容错处理(比如提示 “服务异常”)。 - AIDL 作用:帮我们自动生成
Stub
(服务端实现)和Proxy
(客户端代理)的模板代码,简化跨进程通信的 “编解码”“Binder 调用” 等复杂流程,让我们像写本地接口一样写跨进程逻辑 。
简单说,整个流程就是:客户端绑定服务 → 服务端返回 Binder → 客户端拿到代理 → 代理帮我们做跨进程调用 ,AIDL 主要是帮我们简化了 “代理创建”“数据编解码” 这些繁琐工作~
相关文章:
为什么android要使用Binder机制
1.linux中大多数标准 IPC 场景(如管道、消息队列、ioctl 等)的进程间通信机制 ------------------ ------------------ ------------------ | 用户进程 A | | 内核空间 | | 用户进程 B | | (User Spa…...
Apache SeaTunnel Flink引擎执行流程源码分析
目录 1. 任务启动入口 2. 任务执行命令类:FlinkTaskExecuteCommand 3. FlinkExecution的创建与初始化 3.1 核心组件初始化 3.2 关键对象说明 4. 任务执行:FlinkExecution.execute() 5. Source处理流程 5.1 插件初始化 5.2 数据流生成 6. Transform处理流程 6.1 插…...
XML读取和设置例子
在Qt C中,可以使用Qt的 QDomDocument类来读取、更新和保存XML文件。这个类提供了对XML文档的强大操作能力,支持通过DOM(文档对象模型)对XML进行读取、修改、添加和删除节点等操作。 下面是一个详细的例子,演示如何在Qt…...
数据标注师学习内容
目录 文本标注词性标注实体标注 图像标注语音标注 文本标注 词性标注 第一篇 第二篇 实体标注 点击这里 关系标注 事件标注 意图标注 关键词标注 分类标注 问答标注 对话标注 图像标注 拉框标注 关键点标注 2D标注 3D标注 线标注 目标跟踪标注 OCR标注 图像分类标注 语音…...
如何实现财务自由
如果有人告诉你,普通人也可以在5到10年内,而不是40到50年后实现财务自由、彻底退休,你会不会觉得对方在开玩笑?但这并非天方夜谭,《百万富翁快车道》的作者MJ德马科就是成功案例。他曾和多数人一样做底层工作ÿ…...
一些想法。。。
1.for里面的局部变量这种还是在for里面定义比较好 比如 for(int i 0;i<n;i){ int num; cin>>num; } 实不相瞒,有一次直接cin了i怎么都没看出来哪里错了。。。 2.关于long long 如果发现中间结果大约是10^9,就要考虑int 溢出 即用 long …...
基于分布式部分可观测马尔可夫决策过程与联邦强化学习的低空经济智能协同决策框架
基于分布式部分可观测马尔可夫决策过程与联邦强化学习的低空经济智能协同决策框架 摘要: 低空经济作为新兴战略产业,其核心场景(如无人机物流、城市空中交通、低空监测)普遍面临环境动态性强、个体观测受限、数据隐私敏感及多智能体协同复杂等挑战。本文创新性地提出一种深…...
github常用插件
一,文档辅助阅读系列:自动化wiki处理 1,deepwiki https://deepwiki.com/ 将我们看不懂的官方code文档转换为wiki,更加便于理解。 其实能够翻阅的仓库很有限,比如说: 但是有很多仓库并没有indexÿ…...
python3字典
1 字典简介 字典是一种可变容器模型,且可存储任意类型对象。字典每个基本元素都包括两个部分: 键(key)和键对应的值(value) 每个键值 key>value 对用冒号: 分割,每个对之间用逗号(,)分割&am…...
华为云 Flexus+DeepSeek 征文|增值税发票智能提取小工具:基于大模型的自动化信息解析实践
华为云 FlexusDeepSeek 征文|增值税发票智能提取小工具:基于大模型的自动化信息解析实践 前言背景 企业财务处理中,增值税发票信息手动提取存在效率低、易出错等痛点,华为云 Flexus 弹性算力联合 DeepSeek 大模型,通过…...
[特殊字符] OpenCV opencv_world 模块作用及编译实践完整指南
📌 什么是 opencv_world 模块? opencv_world 是 OpenCV 官方提供的一个 大型集成动态库。它将 OpenCV 所有启用的模块(例如 core, imgproc, highgui, videoio, dnn, photo 等)打包到一个单一的动态库文件(如 Linux 的…...
目标检测之YOLOv5到YOLOv11——从架构设计和损失函数的变化分析
YOLO(You Only Look Once)系列作为实时目标检测领域的标杆性框架,自2016年YOLOv1问世以来,已历经十余年迭代。本文将聚焦YOLOv5(2020年发布)到YOLOv11(2024年前后)的核心技术演进&am…...
Java的SpringAI+Deepseek大模型实战【二】
文章目录 背景交互方式1、等待式问答2、流式问答 设置角色环绕增强1)修改controller2)修改配置日志级别 处理跨域 背景 上篇【Java的SpringAIDeepseek大模型实战【一】】搭建起浏览器交互的环境,如何进行流式问答,控制台打印日志…...
OpenCV——霍夫变换
霍夫变换 一、霍夫变换原理二、霍夫线检测2.1、标准霍夫变换2.2、概率霍夫变换 三、霍夫圆检测3.1、霍夫圆检测的原理3.2、霍夫梯度法 一、霍夫变换原理 霍夫变换(Hough TRansform)是从图像中识别几何图形的基本方法,由Paul Hough于1962年提…...
线程池 JMM 内存模型
线程池 & JMM 内存模型 文章目录 线程池 & JMM 内存模型线程池线程池的创建ThreadPoolExecutor 七大参数饱和策略ExecutorService 提交线程任务对象执行的方法:ExecutorService 关闭线程池的方法:线程池最大线程数如何确定? volatile…...
PillarNet: Real-Time and High-PerformancePillar-based 3D Object Detection
ECCV 2022 paper:[2205.07403] PillarNet: Real-Time and High-Performance Pillar-based 3D Object Detection code:https://github.com/VISION-SJTU/PillarNet-LTS 纯点云基于pillar3D检测模型 网络比较 SECOND 基于vo…...
配电抢修场景案例
以配电抢修场景为例来展示关键业务活动。配电抢修愿景分成业务逻辑、业务活动、业务特征、技术支撑、KPI五个层次,分别从策略、执行、评价、资源、协同5个方面描述配电抢修愿景的关键业务活动。...
H5新增属性
✅ 一、表单相关新增属性(Form Attributes) 这些属性增强了表单功能,提升用户体验和前端验证能力。 1. placeholder 描述:在输入框为空时显示提示文本。示例: <input type"text" placeholder"请输…...
C# Task 模式实现 Demo(含运行、暂停、结束状态)
下面是一个完整的 C# Task 实现示例,包含运行(Running)、暂停(Paused)和结束(Completed)状态控制: 1. 基本实现(使用 CancellationToken 控制) using System; using System.Threading; using System.Threading.Tasks;public cla…...
Docker健康检查
目录 1.命令 2.验证 1.命令 docker run -itd --name nginx -v data:/etc/nginx/ -v log:/var/log/ -p 8080:80 \ --health-cmd"curl http://127.0.0.1:80" \ --health-interval30s \ --health-timeout5s \ --health-retries3 \ --health-start-period18s \ nginx:…...
Linux笔记---线程控制
1. 线程创建:pthread_create() pthread_create() 是 POSIX 线程库(pthread)中用于创建新线程的函数。调用该函数后系统就会启动一个与主线程并发的线程,并使其跳转到入口函数处执行。 #include <pthread.h>int pthread_cr…...
【AI论文】扩展大型语言模型(LLM)智能体在测试时的计算量
摘要:扩展测试时的计算量在提升大型语言模型(LLMs)的推理能力方面已展现出显著成效。在本研究中,我们首次系统地探索了将测试时扩展方法应用于语言智能体,并研究了该方法在多大程度上能提高其有效性。具体而言…...
Spring--IOC容器的一些扩展属性
一、BeanFactoryPostProcessor和BeanPostProcessor BeanFactoryPostProcessor的作用是在实例化前修改BeanDefinition的属性 BeanPostProcessor的作用是在bean完成创建实例、填充属性之后,初始化阶段的前后都会对bean进行操作,使用postProcessBeforeIni…...
WebClient 功能介绍,使用场景,完整使用示例演示
WebClient 功能介绍 WebClient 是 Spring 5 中引入的响应式 HTTP 客户端,用于替代已弃用的 RestTemplate,专为异步非阻塞编程设计,基于 Reactor 框架实现。其核心功能包括: 异步与非阻塞 通过 Mono 和 Flux 处理请求与响应&#…...
[Java 基础]ArrayList
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制。 ArrayList 的示意可以看 VCR:https://visualgo.net/en/array 创建 ArrayList 对象 final ArrayList<String> strings new ArrayList<>();这里创建 …...
用无人机和AI守护高原净土:高海拔自然保护区的垃圾检测新方法
这篇题为《Automatic Detection of Scattered Garbage Regions Using Small Unmanned Aerial Vehicle Low-Altitude Remote Sensing Images for High-Altitude Natural Reserve Environmental Protection》的论文,发表于 Environmental Science & Technology&am…...
《Redis高并发优化策略与规范清单:从开发到运维的全流程指南》
Redis高并发优化策略与规范清单:从开发到运维的全流程指南 在互联网应用的后端架构中,Redis凭借其高性能、高并发的特性,成为缓存和数据存储的首选方案。无论是电商抢购、社交平台的点赞计数,还是在线旅游平台的实时数据查询&…...
Linux基本指令篇 —— man指令
man命令是Linux系统中最重要的命令之一,它是"manual"(手册)的缩写,用于查看Linux系统中命令、函数、配置文件等的详细说明文档。man命令是Linux系统管理员和开发者的必备工具,熟练掌握man命令可以大大提高工…...
Spring Boot使用MCP服务器
1、JDK版本17 2、pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apac…...
学习Linux进程冻结技术
原文:蜗窝科技Linux进程冻结技术 功耗中经常需要用到,但是linux这块了解甚少,看到这个文章还蛮适合我阅读的 1 什么是进程冻结 进程冻结技术(freezing of tasks)是指在系统hibernate或者suspend的时候,将…...
Docker基本概念——AI教你学Docker
1.1 Docker 概念详解 1. Docker 是什么? Docker 是一个开源的应用容器引擎,它让开发者可以将应用及其依赖打包到一个可移植的容器(Container)中,并在任何支持 Docker 的 Linux、Windows 或 macOS 系统上运行。这样做…...
第十六届蓝桥杯C/C++程序设计研究生组国赛 国二
应该是最后一次参加蓝桥杯比赛了,很遗憾,还是没有拿到国一。 大二第一次参加蓝桥杯,印象最深刻的是居然不知道1s是1000ms,花了很多时间在这题,后面节奏都乱了,抗压能力也不行,身体也不适。最后…...
Python 数据分析与可视化 Day 5 - 数据可视化入门(Matplotlib Seaborn)
🎯 今日目标 掌握 Matplotlib 的基本绘图方法(折线图、柱状图、饼图)掌握 Seaborn 的高级绘图方法(分类图、分布图、箱线图)熟悉图像美化(标题、标签、颜色、风格)完成一组学生成绩数据的可视化…...
WebRTC(八):SDP
SDP 概念 SDP 是一种描述多媒体通信会话的文本格式(基于 MIME,RFC 4566)。本身 不传输数据,仅用于在会话建立阶段传递信息。常与 SIP(VoIP)、RTSP、WebRTC 等协议配合使用。 用途 描述媒体类型…...
《哈希表》K倍区间(解题报告)
文章目录 零、题目描述一、算法概述二、算法思路三、代码实现四、算法解释五、复杂度分析 零、题目描述 题目链接:K倍区间 一、算法概述 计算子数组和能被k整除的子数组数量的算法。通过前缀和与哈希表的结合,高效地统计满足条件的子数组。 需要注…...
牛津大学开源视频中的开放世界目标计数!
视频中的开放世界目标计数 GitHub PaPer Niki Amini-Naieni nikianrobots.ox.ac.uk Andrew Zisserman azrobots.ox.ac.uk 视觉几何组(VGG),牛津大学,英国 图 1:视频中的目标计数:给定顶行的视频&#…...
1.2、CAN总线帧格式
1、帧类型 2、帧类型介绍 (1)数据帧 扩展格式是为了扩展ID,ID号每4位一个字节(11位最大ID号为0x7FF) (2)遥控帧 遥控帧由于没有Data,所以DLC可能没有意义,可给任意值&am…...
DeepSeek今天喝什么随机奶茶推荐器
用DeepSeek生成了一个随机奶茶推荐器-今天喝什么,效果非常棒!UI界面美观。 提示词prompt如下 用html5帮我生成一个今天喝什么的网页 点击按钮随机生成奶茶品牌等,要包括中国常见的知名的奶茶品牌 如果不满意还可以随机再次生成 ui界面要好看 …...
词编码模型怎么进行训练的,输出输入是什么,标签是什么
词编码模型怎么进行训练的,输出输入是什么,标签是什么 词编码模型的训练本质是通过数据驱动的方式,将离散的文本符号映射为连续的语义向量。 一、训练机制:从符号到向量的映射逻辑 1. 核心目标 将单词/子词(Token)映射为低维向量,使语义相关的词在向量空间中距离更近…...
LSTM、GRU 与 Transformer网络模型参数计算
参数计算公式对比 模型类型参数计算公式关键组成部分LSTM4 (embed_dim hidden_size hidden_size hidden_size)4个门控结构GRU3 (embed_dim hidden_size hidden_size hidden_size)3个门控结构Transformer (Encoder)12 embed_dim 9 embed_dim ff_dim 14 embed_dim…...
nnv开源神经网络验证软件工具
一、软件介绍 文末提供程序和源码下载 用于神经网络验证的 Matlab 工具箱,该工具箱实现了可访问性方法,用于分析自主信息物理系统 (CPS) 领域中带有神经网络控制器的神经网络和控制系统。 二、相关工具和软件 该工具箱利用神经…...
SQLite3 在嵌入式系统中的应用指南
SQLite3 在嵌入式系统中的应用指南 一、嵌入式系统中 SQLite3 的优势 SQLite3 是嵌入式系统的理想数据库解决方案,具有以下核心优势: 特性嵌入式系统价值典型指标轻量级适合资源受限环境库大小:500-700KB零配置无需数据库管理员开箱即用无…...
原生微信小程序网络请求与上传接口封装实战指南
本文基于微信小程序原生 API,封装 request 和 uploadFile 接口,最终实现统一请求管理、请求拦截、错误处理等能力。 📦 一、为什么要封装网络请求? 微信小程序提供了 wx.request 和 wx.uploadFile 原生 API,但直接使用…...
电路图识图基础知识-塔式起重机控制电路识图与操作要点(三十五)
引言: 塔式起重机作为建筑施工中不可或缺的大型起重运输机械设备,其控制电路的识图与操作对于确保施工安全和效率至关重要。本文将详细介绍塔式起重机的控制电路识图,帮助操作人员更好地理解和掌握其工作原理。 一、塔式起重机概述 塔式起重…...
基于SpringBoot + Vue 的网上拍卖系统
基于springbootvue的在线拍卖系统| Java | vue | 配万字文档 | springboot001 〔运行环境〕 Java版本:jdk1.8 node版本:13.x python版本:2.7 IDE类型:idea或exlipse 数据库:MySQL(5.x或8.x版本都…...
用 EXCEL/WPS 实现聚类分析:赋能智能客服场景的最佳实践
聚类分析作为无监督学习的核心技术,能在客服数据中发现隐藏的用户群体或问题模式。尽管 Excel/WPS 并非专业统计软件,但巧妙利用其内置功能,也能实现基础的聚类分析,为中小型客服团队提供快速洞察。以下介绍具体方法及智能客服场景…...
利用mold加快rust程序构建
我用rust的cargo build命令编译polars-cli时,用时达到14分钟,如下所示。 Finished dev profile [unoptimized debuginfo] target(s) in 14m 19s,通过核对时间戳,发觉其中最后一步生成可执行文件花了6分钟。 于是向DeepSeek请教&a…...
leetcode543-二叉树的直径
leetcode 543 思路 路径长度计算:任意两个节点之间的路径长度,等于它们的最低公共祖先到它们各自的深度之和递归遍历:通过后序遍历(左右根)计算每个节点的左右子树深度,并更新全局最大直径深度与直径的关…...
(三)yolov5——模型训练
一、准备数据 先准备一个MP4的视频 1.测试一帧 使用opencv来提取每一个视频的帧 先使用以下代码查看一帧的内容,是否符合预期 import cv2 import matplotlib.pyplot as plt# 打开视频文件 video cv2.VideoCapture("111.mp4") # 读取一帧 ret, frame…...
STM32对接霍尔传感器
STM32对接霍尔传感器的技术解析与应用实现,结合测速原理、硬件设计、代码实现及进阶应用,涵盖从基础到实战的全流程指南,可以应用到金属检测等功能。 ⚙️ 一、霍尔传感器基础 工作原理 霍尔传感器基于霍尔效应,当磁铁靠近时输出电平变化(常开型无磁铁时输出高电平,靠近时…...