基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化
基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化
1. 输出关键信息的代码示例
日志记录方法
使用以下代码记录连接池的关键信息,帮助分析连接池的状态和性能瓶颈:
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class GrpcChannelPoolAnalyzer {private static final Logger logger = LoggerFactory.getLogger(GrpcChannelPoolAnalyzer.class);private final GenericObjectPool<GrpcChannel> grpcChannelPool;public GrpcChannelPoolAnalyzer(GenericObjectPool<GrpcChannel> grpcChannelPool) {this.grpcChannelPool = grpcChannelPool;}public void logPoolStatus() {logger.info("=== GrpcChannelPool Status ===");logger.info("Num Active: {}", grpcChannelPool.getNumActive());logger.info("Num Idle: {}", grpcChannelPool.getNumIdle());logger.info("Num Waiters: {}", grpcChannelPool.getNumWaiters());logger.info("Total Borrowed Count: {}", grpcChannelPool.getBorrowedCount());logger.info("Total Created Count: {}", grpcChannelPool.getCreatedCount());logger.info("Total Returned Count: {}", grpcChannelPool.getReturnedCount());logger.info("Total Destroyed Count: {}", grpcChannelPool.getDestroyedCount());}
}
调用日志记录
public static void main(String[] args) {// 创建连接池GenericObjectPool<GrpcChannel> grpcChannelPool = new GenericObjectPool<>(new GrpcChannelFactory());// 初始化分析器GrpcChannelPoolAnalyzer analyzer = new GrpcChannelPoolAnalyzer(grpcChannelPool);// 定期输出日志analyzer.logPoolStatus();
}
2. 关键方法的含义和影响分析
A. getBorrowedCount()
- 含义:
- 自池创建以来,成功借出的对象总数。
- 表示连接池处理了多少次借用请求。
- 可能的影响:
- 如果
getBorrowedCount很高,说明连接池被频繁借用。这可能导致以下问题:- 如果连接池配置的
maxTotal过低,导致线程排队等待可用连接。 - 如果池中连接被频繁销毁或验证失败,导致额外的连接创建开销。
- 如果连接池配置的
- 借用连接时慢可能是由于等待连接归还或新建连接的时间过长。
- 如果
B. getCreatedCount()
- 含义:
- 自池创建以来,总共创建的对象数量。
- 包括了所有当前活跃、空闲和已销毁的对象。
- 可能的影响:
- 如果
getCreatedCount很高,表明连接池频繁创建新连接,可能是因为:- 空闲连接销毁过快:池中配置了较小的
maxIdle或空闲对象检测频率较高,导致连接被频繁销毁。 - 验证失败:连接在借用时被标记为无效,从而需要创建新连接。
- 连接使用时间长:池内的连接未及时归还,导致新连接不断创建。
- 空闲连接销毁过快:池中配置了较小的
- 借用连接时慢可能是由于新连接创建速度较慢(如涉及网络请求、SSL 加密等复杂逻辑)。
- 如果
C. getNumActive()
- 含义:
- 当前正在被使用的连接数。
- 可能的影响:
- 如果
getNumActive接近或等于maxTotal:- 新的借用请求将被阻塞,等待有连接归还或新建。
- 借用延迟的时间取决于前一个连接释放的速度或新连接创建时间。
- 如果
D. getNumIdle()
- 含义:
- 当前池中空闲的连接数。
- 可能的影响:
- 如果
getNumIdle为 0,意味着没有可立即借用的连接。 - 此时,借用请求会被阻塞,直到:
- 一个连接被归还。
- 一个新连接被创建。
- 借用连接时慢通常与空闲连接耗尽直接相关。
- 如果
E. getNumWaiters()
- 含义:
- 当前等待借用连接的线程数。
- 可能的影响:
- 如果等待线程数较多,表明连接池无法及时满足请求。
- 这种情况可能因为
maxTotal设置过低或连接释放速度过慢导致。
F. getDestroyedCount()
- 含义:
- 自池创建以来,被销毁的连接总数。
- 可能的影响:
- 如果销毁的连接数较高,可能导致借用连接时需要频繁创建新连接,从而增加延迟。
- 检查空闲对象的检测配置是否合理(如
timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis)。
3. 借用对象慢的分析原因
根据以上信息,以下是常见可能的原因及解决方案:
原因 1:空闲连接不足
- 表现:
getNumIdle为 0。 - 分析:池中没有空闲连接供借用,新的借用请求需要等待归还或创建新连接。
- 解决方案:
- 增加
minIdle和maxIdle,确保有足够的空闲连接。 - 减少连接创建的开销(优化
makeObject()方法)。
- 增加
原因 2:线程等待超时
- 表现:
getNumWaiters高,getNumActive接近或等于maxTotal。 - 分析:借用请求太多,超过了池的最大容量。
- 解决方案:
- 增加
maxTotal,允许池处理更多并发连接。 - 优化业务逻辑,减少连接使用时间。
- 增加
原因 3:连接频繁销毁和创建
- 表现:
getCreatedCount和getDestroyedCount较高。 - 分析:可能因连接超时、验证失败或空闲销毁策略不合理导致。
- 解决方案:
- 调整连接池的空闲销毁参数(如
timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis)。 - 优化连接验证逻辑,减少验证失败的情况。
- 调整连接池的空闲销毁参数(如
原因 4:连接创建耗时
- 表现:
getNumActive达到maxTotal,getNumIdle为 0。 - 分析:新连接的创建时间太长,可能因网络延迟、认证复杂或初始化慢。
- 解决方案:
- 优化连接的创建过程(减少网络调用、使用连接池化资源)。
- 预热池:配置
minIdle和定期检测任务。
4. 日志输出与示例分析
假设运行时日志输出如下:
INFO - === GrpcChannelPool Status ===
INFO - Num Active: 10
INFO - Num Idle: 0
INFO - Num Waiters: 95
INFO - Total Borrowed Count: 500
INFO - Total Created Count: 520
INFO - Total Destroyed Count: 10
分析
-
Num Idle = 0
- 空闲连接不足,导致新的借用请求需要等待。
-
Num Waiters = 95
- 表示 95 个线程正在等待借用连接,系统压力较大。
-
Total Created Count = 520,Total Destroyed Count = 10
- 表明创建频率高,销毁频率低,可能是空闲检测频率较低或借用时触发新连接的创建逻辑。
解决方案
- 增加
maxTotal(如 50)。 - 设置合理的
minIdle(如 10)并启用预热机制。 - 优化连接创建速度,减少延迟。
5. 如何获取 maxTotal 与其关系
获取 maxTotal 的方法
maxTotal 是连接池中可同时活跃对象的最大数量。在 Apache Commons Pool 中,通过 GenericObjectPoolConfig 设置并管理此参数。
获取 maxTotal 的代码
如果你有一个 GenericObjectPool 实例,可以通过以下代码获取 maxTotal 的值:
int maxTotal = grpcChannelPool.getMaxTotal();
System.out.println("Max Total: " + maxTotal);
maxTotal 与 NumActive 的关系
定义
-
maxTotal:- 定义了连接池中允许同时活跃的最大对象数量。
- 当活跃对象数量达到
maxTotal时,新的借用请求会被阻塞,直到有对象归还或超时。
-
NumActive:- 表示当前池中被借用(活跃使用)的对象数量。
NumActive的值始终小于或等于maxTotal。
关系描述
-
NumActive ≤ maxTotal:NumActive是当前实际使用的对象数量,受maxTotal的限制。- 如果
NumActive达到maxTotal,连接池不会再创建新对象,而是让新的请求进入等待状态。
-
连接池满的场景:
- 当
NumActive == maxTotal且NumIdle == 0时,连接池满载,新的借用请求将进入等待队列,直到有对象被归还或超时。
- 当
-
调整
maxTotal的影响:- 增加
maxTotal:允许池支持更多并发请求,但需要足够的系统资源(如数据库连接数)。 - 减少
maxTotal:限制池的最大并发能力,可能导致更多请求进入等待队列。
- 增加
示例分析
代码示例
以下代码展示如何获取 maxTotal 和检查其与 NumActive 的关系:
import org.apache.commons.pool2.impl.GenericObjectPool;public class PoolStatusChecker {public static void logPoolStatus(GenericObjectPool<?> pool) {int maxTotal = pool.getMaxTotal();int numActive = pool.getNumActive();int numIdle = pool.getNumIdle();System.out.println("Max Total: " + maxTotal);System.out.println("Num Active: " + numActive);System.out.println("Num Idle: " + numIdle);if (numActive == maxTotal && numIdle == 0) {System.out.println("Connection pool is at full capacity.");}}
}
运行结果示例
假设运行时的池状态如下:
Max Total: 10
Num Active: 10
Num Idle: 0
分析:
- 当前活跃连接数
NumActive = 10已经达到maxTotal。 - 此时,如果有新的借用请求,将进入等待队列,可能导致延迟。
总结
maxTotal定义了池中最大同时活跃对象的数量,而NumActive是当前实际使用的对象数量。NumActive始终小于或等于maxTotal,当NumActive == maxTotal且NumIdle == 0时,新的借用请求将进入等待状态。- 根据业务需求动态调整
maxTotal,并结合NumActive和NumWaiters的监控数据,优化连接池配置。
GrpcChannelPool 性能分析与数学关系
1. 关键值的意义和关系
活跃连接数 (NumActive)
- 当前正在使用的连接数量。
NumActive ≤ maxTotal(活跃连接不能超过最大连接数)。
空闲连接数 (NumIdle)
- 当前池中未被使用的连接数量。
NumIdle + NumActive ≤ maxTotal(空闲和活跃连接之和不能超过池中允许的最大连接数)。
等待线程数 (NumWaiters)
- 当前等待借用连接的线程数。
- 当
NumActive == maxTotal且NumIdle == 0时,新的请求进入等待队列,此时NumWaiters > 0。
最大连接数 (maxTotal)
- 池中允许的最大同时活跃连接数。
- 限制了
NumActive和NumIdle的上限。
2. 累积统计值
借用总数 (Total Borrowed Count)
- 表示自池创建以来成功借出的对象总数。
Total Borrowed Count ≥ NumActive(历史借用次数必然大于或等于当前活跃数)。
创建总数 (Total Created Count)
- 表示自池创建以来创建的对象总数。
Total Created Count ≥ NumActive + NumIdle(当前池中活跃和空闲连接数量必须由创建的连接数提供)。
归还总数 (Total Returned Count)
- 表示自池创建以来归还的对象总数。
Total Returned Count = Total Borrowed Count - NumActive(归还的连接数等于借用总数减去当前未归还的活跃连接数)。
销毁总数 (Total Destroyed Count)
- 表示自池创建以来销毁的对象总数。
Total Destroyed Count = Total Created Count - (NumActive + NumIdle)(销毁的连接数等于创建的连接数减去池中当前剩余的活跃和空闲连接)。
3. 主要数学运算关系

4. 示例分析
假设运行时池的状态如下:
maxTotal = 10NumActive = 6NumIdle = 2NumWaiters = 3Total Borrowed Count = 50Total Created Count = 15Total Returned Count = 44Total Destroyed Count = 7
验证数学关系:

5. 如何利用这些关系分析性能问题
通过以上数学关系,可以监控和诊断连接池的问题。例如:
池容量不足
- 表现:
- 如果
NumActive + NumIdle长期接近或等于maxTotal,且NumWaiters > 0。
- 如果
- 原因:
- 连接池容量不足,导致大量线程排队。
- 解决方案:
- 增加
maxTotal。
- 增加
连接泄漏
- 表现:
- 如果
Total Borrowed Count - Total Returned Count ≠ NumActive。
- 如果
- 原因:
- 存在未归还的连接。
- 解决方案:
- 检查业务代码,确保每次借用的连接都正确归还。
连接频繁创建销毁
- 表现:
- 如果
Total Destroyed Count很高。
- 如果
- 原因:
- 连接被频繁销毁,可能是因为空闲策略不合理。
- 解决方案:
- 调整
minIdle和空闲销毁参数。
- 调整
6. 总结
这些值之间的数学关系提供了诊断连接池运行状态的重要依据。通过监控和分析这些关系,可以:
- 优化连接池的配置(如
maxTotal、minIdle等)。 - 发现性能瓶颈(如等待时间过长、连接不足等)。
- 及时修复问题(如连接泄漏或资源浪费)。
GrpcChannelPool 预热机制详解
1. 预热机制的概念
预热机制是指在连接池启动时或者空闲连接不足时,预先创建一定数量的连接(由 minIdle 参数指定),以确保在请求到来时能够快速响应,避免因为连接创建而导致延迟。
在 Apache Commons Pool 中,预热机制通过以下参数实现:
minIdle: 定义了连接池中保持的最小空闲连接数。如果空闲连接少于这个值,连接池会主动补充连接。timeBetweenEvictionRunsMillis: 定义了空闲对象检测线程的运行周期。如果设置了该值,后台线程会定期运行,确保空闲连接数不低于minIdle。numTestsPerEvictionRun: 定义每次检测时要检查的对象数量。
2. 如何启用预热机制
步骤 1: 设置 minIdle
- 定义连接池的最小空闲连接数。例如,如果你的系统需要至少保持 5 个连接可以快速响应:
poolConfig.setMinIdle(5);
步骤 2: 启用空闲检测线程
- 设置
timeBetweenEvictionRunsMillis,让连接池定期检查和补充空闲连接。例如:poolConfig.setTimeBetweenEvictionRunsMillis(10000); // 每 10 秒运行一次检测任务
步骤 3: 确保足够的空闲连接
- 设置
numTestsPerEvictionRun,控制每次检测的对象数量。通常设置为一个较大的值(如-1,表示检测所有对象):poolConfig.setNumTestsPerEvictionRun(-1);
可选参数
testWhileIdle:- 如果设置为
true,连接池会在补充空闲连接时验证连接是否有效。 - 适合场景:如果连接容易失效(例如网络中断),启用此参数可提高连接池的可靠性。
- 如果设置为
3. 完整的预热机制代码示例
以下是一个示例,展示如何为连接池启用预热机制:
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;public class GrpcChannelPoolConfig {public static GenericObjectPoolConfig<Object> createConfig() {GenericObjectPoolConfig<Object> poolConfig = new GenericObjectPoolConfig<>();// 设置连接池大小poolConfig.setMaxTotal(50); // 最大连接数poolConfig.setMinIdle(5); // 最小空闲连接数poolConfig.setMaxIdle(10); // 最大空闲连接数// 启用预热机制poolConfig.setTimeBetweenEvictionRunsMillis(10000); // 每 10 秒检测一次poolConfig.setNumTestsPerEvictionRun(-1); // 每次检测所有对象poolConfig.setTestWhileIdle(true); // 检查空闲连接有效性return poolConfig;}
}
4. 预热机制的优点
- 减少首次延迟:在请求到达前已创建好足够的连接,无需等待连接创建。
- 提高系统响应能力:尤其在负载波动较大的场景下,预热机制能缓解连接不足的问题。
- 提升可靠性:通过定期检测和补充空闲连接,确保池中连接始终处于健康状态。
5. 注意事项
-
监控连接数量:
- 如果设置了过大的
minIdle,可能导致资源浪费(如内存、数据库连接等)。 - 建议通过监控工具(如 JMX)观察实际连接使用情况,动态调整参数。
- 如果设置了过大的
-
创建时间消耗:
- 如果连接创建耗时较长(如 SSL 或远程服务连接),建议适当增加
timeBetweenEvictionRunsMillis的间隔,避免频繁创建。
- 如果连接创建耗时较长(如 SSL 或远程服务连接),建议适当增加
-
避免过度销毁:
- 配置
maxIdle和minIdle的差距不宜过大,防止频繁的连接创建和销毁。
- 配置
6. 总结
预热机制的核心是通过配置 minIdle 和空闲检测线程定期补充连接,以确保空闲连接数不低于 minIdle。启用预热机制的关键配置是:
setMinIdle:定义最小空闲连接数。setTimeBetweenEvictionRunsMillis:定期检测周期。- 可选:启用
testWhileIdle提高连接有效性检测。
这些参数协同工作,可以显著提高连接池的性能和响应能力。
相关文章:
基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化
基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化 1. 输出关键信息的代码示例 日志记录方法 使用以下代码记录连接池的关键信息,帮助分析连接池的状态和性能瓶颈: import org.apache.commons.pool2.impl.GenericO…...
【C语言】
目录 第一个C语言程序题目实际应用程序要求输入描述输出描述示例 程序实现三级目录 第一个C语言程序 打开VS创建项目(视图-解决方案管理器)创建源文件(后缀.c).c会按照C的语言编译代码 c #include <stdio.h> //std-标准 //…...
标题:利用Spring Boot构建JWT刷新令牌应用
标题:利用Spring Boot构建JWT刷新令牌应用 去发现同类优质开源项目:https://gitcode.com/ 一、项目介绍 在Java开发中,Spring Boot以其简洁的配置和强大的功能深受开发者喜爱。Spring Boot Refresh Token with JWT 是一个开源示例项目,它展…...
性能测试工具的原理与架构解析
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 在软件开发与运维领域,性能测试是确保系统稳定、高效运行的关键环节。性能测试工具作为实现这一目标的重要工具,通过模拟真实用户行为和负载…...
基于STM32的自动水满报警系统设计
目录 引言系统设计 硬件设计软件设计系统功能模块 水位检测模块报警模块自动控制模块控制算法 水位检测逻辑报警触发逻辑代码实现 水位检测模块报警控制模块自动控制逻辑系统调试与优化结论与展望 1. 引言 水满报警系统在家庭、农业、工业等领域广泛应用,通过实时…...
C语言 数组编程练习
1.将数组A的内容和数组B中的内容进行交换。(数组一样大) 2.创建一个整形数组,完成对数组的操作 实现函数Init()初始化数组全为0 实现print()打印数组的每个元素 实现reverse()函数完成数组元素的逆置 //2.创建一个整形数组,完…...
Windows 远程桌面连接Ubuntu操作 可以自由相互复制文件 粘贴板等
1.windows不用动,用IP和用户密码直接连 Ubuntu设置 详细参考:https://blog.csdn.net/qq_22370409/article/details/88914093 新建的用户需要加入sudo 使有权限。 效果 可以自由相互复制文件 粘贴板等。...
链表OJ题(一)
(一)轮转数组 . - 力扣(LeetCode) 题目描述:给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例一: 方法一:暴力求解 先用一个变量存储数组中的最后…...
C/C++中new/delete与malloc/free的区别及对象管理
C/C++中new/delete与malloc/free的区别及对象管理 在C/C++编程中,动态内存管理是一个核心且复杂的话题,其中new、delete、malloc和free是四个经常用于此目的的工具。尽管它们都涉及到内存的分配和释放,但它们在处理对象时的方式和效果却大相径庭。本文将通过示例来说明这些工…...
我的nvim的init.lua配置
nvim的配置文件路径在~/.config/nvim路径下: 一、目录如下: coc-settings.json文件是配置代码片段路径的文件init.lua配置文件的启动脚本lua/config.lua 全局配置文件lua/keymaps.lua 快捷键映射键文件lua/plugins.lua 插件的安装和配置文件…...
2025第1周 | JavaScript中的正则表达式
目录 1. 正则表达式是个什么东东?1.1 怎么定义正则1.2 对象字面量方式1.3 类创建方式 2. 怎么使用2.1 实例方法2.1.1 exec方法2.1.2 test方法 2.2 字符串中的方法2.2.1 match/matchAll2.2.2 replace/replaceAll2.2.3 split2.2.4 search 3. 规则3.1 修饰符3.2 字符类…...
基于 Python Django 的西西家居全屋定制系统(源码+部署+文档)
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
【Leetcode 热题 100】74. 搜索二维矩阵
问题背景 给你一个满足下述两条属性的 m n m \times n mn 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 t a r g e t target target,如果 t a r g e t target target 在矩阵中&…...
讯方技术入库深圳市第一批建设培育产教融合型企业
产教融合是指产业与教育的紧密结合,是现代职业教育体系的重要组成部分。通过企业与学校之间的合作,使学生在学校所学的知识和技能能够更好地满足企业和社会的实际需求,同时也为企业提供高素质的技术人才,促进产业升级和经济发展。…...
阿里云代理商热销产品推荐
在数字化浪潮的推动下,企业对于云计算的依赖日益加深。阿里云,作为中国领先的云计算服务提供商,为企业提供了丰富多样的云产品和服务。本文将聚焦于阿里云代理商热销产品推荐,探讨其如何帮助企业高效利用云资源,加速数…...
海外云服务器能用来做什么?
海外云服务器不仅服务种类繁多,而且能满足多行业的需求,方便了越来越多的企业与个人。本文将探讨海外云服务器的核心服务及其适用领域,帮助企业更好地了解这一技术资源。 云存储:安全高效的数据管理 海外云服务器为用户提供了稳定…...
LeetCode 704 如何正确书写一个二分查找
题目链接 中文版:https://leetcode.cn/problems/binary-search/description/ 题目描述 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标…...
基于springboot+vue的餐饮连锁店管理系统的设计与实现
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...
transfomer深度学习实战水果识别
本文采用RT-DETR作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。RT-DETR以其高效的实时检测能力,在多个目标检测任务中展现出卓越性能。本研究针对水果数据集进行训练和优化,该数据集包含丰富的水果图像样本&#…...
【CPU】堆栈和堆栈指针(个人草稿)
详细的 CPU 中堆栈指针(Stack Pointer, SP)及相关知识介绍 1. 什么是堆栈? 堆栈(Stack) 是一种后进先出(LIFO, Last In First Out)的数据结构,广泛用于计算机系统中,尤…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
