当前位置: 首页 > news >正文

记一次调用大华抓拍SDK并发优化

 

目录

一、问题分析

二、解决思路

三、贴代码

四、总结 


一、问题分析

按惯例上问题:

  • 设备告警采用高电平持续模式:一次开,不主动关就一直处于告警状态。

  • 并发时多个请求下发 setDVRAlarmOutConfig,导致状态混乱。

  • “开 -> 睡眠 -> 关” 这个链路若被中断或未串联,会导致设备长期处于告警状态,后续指令失效。

  • 有些设备存在 SDK 偶发失败或无响应等问题。

二、解决思路

  •  避免并发打断流程对每个 deviceIdsynchronized 锁;
  • 设置告警时做 两次兜底关
  • 使用线程池异步执行告警任务

三、贴代码

// 全局设备锁容器
private static final ConcurrentHashMap<String, Object> deviceLocks = new ConcurrentHashMap<>();
// 告警线程池(你可以封装成 @Async 或自己定义线程池)
private static final ExecutorService alarmExecutor = Executors.newFixedThreadPool(10);@GetMapping("autoAlarm")
@Operation(summary = "自动告警")
@Parameter(name = "deviceId", description = "设备ID", required = true)
@Parameter(name = "duration", description = "告警持续时间 单位 毫秒(不能超过10000毫秒)", required = true)
public CommonResult<String> autoAlarm(@RequestParam String deviceId, @RequestParam Integer duration) {Assert.isTrue(duration <= 10000, () -> new ServiceException("告警持续时间不能超过10000毫秒"));DeviceInfo info = SdkDevice.getDevice(deviceId);Assert.notNull(info, () -> new ServiceException(GlobalErrorCodeConstants.DEVICE_NOT_EXIST.getCode(),StrUtil.format("设备[{}]未注册", deviceId)));Assert.isTrue(info.getLoginHandle().longValue() > 0,() -> new ServiceException(GlobalErrorCodeConstants.DEVICE_UN_REGISTERED.getCode(), "设备未注册"));alarmExecutor.submit(() -> {Object lock = deviceLocks.computeIfAbsent(deviceId, k -> new Object());synchronized (lock) {try {// step 1. 开启告警输出NetSDKLib.CFG_ALARMOUT_INFO onConfig = DhSdkServer.getDVRAlarmOutConfig(info.getLoginHandle(), deviceId);log.info("[{}] 设置前 mode: {}", deviceId, onConfig.nOutputMode);boolean open = DhSdkServer.setDVRAlarmOutConfig(info.getLoginHandle(), onConfig, 1, info.getAlarmChannelId(), deviceId);if (!open) {log.warn("[{}] 告警打开失败", deviceId);return;}log.info("[{}] 告警已打开,持续 {} 毫秒", deviceId, duration);ThreadUtil.sleep(duration);// step 2. 关闭告警输出boolean firstClose = tryCloseAlarm(info, deviceId, "first");if (!firstClose) {ThreadUtil.sleep(200);tryCloseAlarm(info, deviceId, "fallback");}} catch (Exception ex) {log.error("[{}] 告警流程异常: {}", deviceId, ex.getMessage(), ex);}}});return CommonResult.success("告警任务已下发,后台执行");
}private boolean tryCloseAlarm(DeviceInfo info, String deviceId, String phase) {try {NetSDKLib.CFG_ALARMOUT_INFO offConfig = DhSdkServer.getDVRAlarmOutConfig(info.getLoginHandle(), deviceId);boolean result = DhSdkServer.setDVRAlarmOutConfig(info.getLoginHandle(), offConfig, 2, info.getAlarmChannelId(), deviceId);log.info("[{}] {} 阶段关闭告警结果: {}", deviceId, phase, result);return result;} catch (Exception e) {log.warn("[{}] {} 阶段关闭异常: {}", deviceId, phase, e.getMessage());return false;}
}

四、总结 

  • 每个设备串行执行(防止并发导致状态错乱) 
  • 自动“兜底”第二次关闸
  • 不阻塞主线程(可支撑高并发请求)
http://www.xdnf.cn/news/143947.html

相关文章:

  • 第R4周:LSTM-火灾温度预测
  • QtDesigner中Button控件详解
  • 七、函数重载与默认参数(Function Overloading Default Arguments)
  • SQL 函数进行左边自动补位fnPadLeft和FORMAT
  • 明远智睿SD2351核心板:以48元撬动AI视觉产业革命的“硬核引擎”
  • 第四章第四节 Spark-Streaming核心编程(三)
  • 优化非线性复杂系统的参数
  • 2025年大语言模型平台、主流模型及Token价格的综合对比分析报告
  • ThinkPHP6模型中多组条件逻辑或Or查询的使用
  • 雪花算法:分布式系统唯一 ID 生成的核心方案
  • 【持续更新】 CDC 跨时钟域处理
  • SQLite 是什么?
  • qt中写一个简易的计算器
  • 深入理解 RUM(真实用户监控)与前端锚点的应用与实践
  • LLM自回归模型:在输入输出中构建关系图的隐式表达
  • Python自动化解决滑块验证码的最佳实践
  • Vue3 自定义指令完全指南
  • 拥有600+门店的宠物连锁医院,实现核心业务系统上云
  • 科技与商业动态简报
  • Linux内核参数调优(TCP BBR算法实践)
  • 文件传输过滤器绕过:Exe2Hex
  • Dapper的数据库操作备忘
  • STM32MPU开发之旅:从零开始构建嵌入式Linux镜像
  • 高职人工智能技术应用专业(计算机视觉方向)实训室解决方案
  • WordPress AI 原创文章自动生成插件 24小时全自动生成SEO原创文章 | 多语言支持 | 智能配图与排版
  • 本土网盟推广孟加拉slot游戏出海营销优势
  • CSS常遇到自适应高度动画、带三角气泡阴影一行样式解决
  • 鸿蒙NEXT开发剪贴板工具类(ArkTs)
  • 智慧医院建设的三大关键领域
  • [AI技术(二)]JSONRPC协议MCPRAGAgent