基于 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)的数据结构,广泛用于计算机系统中,尤…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
使用homeassistant 插件将tasmota 接入到米家
我写一个一个 将本地tasmoat的的设备同通过ha集成到小爱同学的功能,利用了巴法接入小爱的功能,将本地mqtt转发给巴法以实现小爱控制的功能,前提条件。1需要tasmota 设备, 2.在本地搭建了mqtt服务可, 3.搭建了ha 4.在h…...
【JavaEE】万字详解HTTP协议
HTTP是什么?-----互联网的“快递小哥” 想象我们正在网上购物:打开淘宝APP,搜索“蓝牙耳机”,点击商品图片,然后下单付款。这一系列操作背后,其实有一个看不见的“快递小哥”在帮我们传递信息,…...
Go 并发编程基础:select 多路复用
select 是 Go 并发编程中非常强大的语法结构,它允许程序同时等待多个通道操作的完成,从而实现多路复用机制,是协程调度、超时控制、通道竞争等场景的核心工具。 一、什么是 select select 类似于 switch 语句,但它用于监听多个通…...
