当前位置: 首页 > 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;}
}

四、总结 

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

相关文章:

  • 多模态深度学习: 从基础到实践
  • 网络犯罪全球化,数字时代的跨国诈骗危机
  • 文件的读取操作
  • 7年经验的Java程序员的技术知识概览(及分阶段学习计划、资源推荐、职业发展建议)
  • Web Worker 线程通信
  • Vue回调函数中的this
  • 8. 深入Spring AI:自定义Advisor
  • 函数的定义与使用(python)
  • 十五、项目管理
  • Prometheus中部署Alertmanager
  • 基于 Python 的自然语言处理系列(85):PPO 原理与实践
  • 70.评论日记
  • Kubernetes in action-初相识
  • C++ 类及函数原型详解
  • 通过模仿学习实现机器人灵巧操作:综述(上)
  • 船舶参数(第一版)
  • 交叉熵损失函数:从信息量、熵、KL散度出发的推导与理解
  • 动态规划算法详解(C++)
  • 使用Tortoise-ORM和FastAPI构建评论系统
  • RDK X3新玩法:超沉浸下棋机器人开发日记
  • 人民日报任仲平:为什么中国意味着确定性、未来性、机遇性
  • 为国出征指纹却无法识别?他刷新了我军在这一项目的最好成绩
  • 四川省人大常委会原党组成员、副主任宋朝华接受审查调查
  • “80后”李岩已任安徽安庆市领导
  • 传染病防治法修订草案:拟加强医疗机构疾病预防控制能力建设
  • 3岁男童疑遭父亲虐待,杭州警方:在异地发生,嫌疑人已被抓