背景:小区地下停车场,需要接入摄像头抓图做识别,然后控制开关灯
一、抓图优化
1、多线程全流程并发
思路:
- 获取摄像头数据
- 为每个摄像头分配一个线程,在这个线程中执行:抓图、分析、处理的工作
遇到的问题:
- 线程池很快就满了,后面的任务全部被拒绝
原因:
- 算法服务不支持多线程,导致任务全部阻塞
2、多线程分组检测
思路:
- 1、调度线程并发抓摄像头图片
- 2、等待所有摄像头图片抓完
- 3、对图片进行分组,每组10个调用算法进行并行分析
- 4、算法分析结束后执行后续逻辑
- 5、等待所有线程组结束之后重新开始执行1
线上运行情况:
- 1、并发抓图,摄像头的抓图时间会越来越长,从第一个摄像头抓图的20ms到最后一个摄像头抓图的1000ms
- 2、算法分析时长在500ms到1500ms之间,平均在1000ms
- 3、整个流程执行时长平均在3000ms
可能的原因:
- 1、摄像头抓图使用sdk,可能不支持并发抓图
- 2、算法分析时长因为是10张图片同时分析,平均下来一张在100ms左右
3、双线程多图片分析
这个阶段,算法那边支持了多张图片一起分析。
主要优化摄像头抓图的逻辑
思路:
- 1、调度一个线程单独执行抓图,单线程、for循环一直抓,抓到的图片缓存起来
- 2、调度一个线程消费图片缓存,以10张图片为目标,调用算法分析
- 3、将摄像头抓图的数量和算法分析的数量记录下来,先定时打印一下
存在的问题:
- 1、算法服务器平均2600ms
- 2、单张抓图30ms
- 3、平均丢图片45%
- 4、消费一轮图片平均耗时2700ms
4、6线程并发抓图
思路:将摄像头平分到6个线程中,线程中串行抓图,线程间并发抓图
最后的效果:
- 一个线程8路摄像头,500ms抓完一轮
二、压缩优化
算法在版本3中支持图片压缩后分析,所以抓完图片之后需要压缩在分析。
1、多线程压缩
起了一个单独的线程池,核心线程10,最大线程50,阻塞队列0(不能等待,因为如果不是0,那么第11个请求会入对而不是起一个新线程处理)
问题:
- 1920 * 1080的图片压缩到320 * 180平均一张需要500ms左右,猜测是上下文切换和线程争抢导致的问题
- 手写的压缩算法和thumbnailator都是这个效果
2、opencv压缩
换了opencv库之后,单张图片平均压缩时间在20ms左右,然后就将图片的压缩放到和抓图一起了,就是抓完图立马压缩
三、分析优化
1、单线程单图片
这时算法只支持一张图片一张图片分析,此时程序瓶颈主要在算法
2、单线程多图片
算法支持多张图片同时分析
问题:
- 多张图片识别时间过长,最长要10s+
3、3并发图片压缩分析
算法支持最多3个并发,同时将图片压缩成320*180比例,加快图片传输效率
效果:
- 15张图片分析平均在300ms以下
四、开关逻辑优化
开关使用lora无线连接DTU,控制指令只下发给DTU,DTU是半双工。
1、无限制
当需要开|关时直接下发指令。
问题
- 遇到开关打不开的情况(发太快把信道堵死了)
2、串行发送
将所有需要下发的指令串行发下去
问题
- 还是会遇到打不开的情况
3、往DTU同步状态
每1秒中向DTU同步开关在系统中的状态
问题:
- 指令需要排队,遇到同时需要打开多个开关的情况延迟会比较高
4、优先级队列+事件循环
需要下发的指令按照优先级放入队列(开灯指令>关灯指令>其他指令),采用事件循环+异步回调机制往下发指令,下发一个指令之后等待指令结果(超时时间1秒)。等待到结果之后立即处理下一个指令,超时之后将指令重新入队。
效果:开灯时间控制在1秒以内
五、流程优化
1、单摄像头并发
一个摄像头一个线程,抓图、分析、处理全在一个线程中处理完之后在重新抓图、分析、处理
问题:
- 算法不支持这么高的并发分析
- 整个流程的延迟非常高
2、分组检测
摄像头并发抓图,抓完之后分组调用算法分析,然后处理结果
问题:
- 摄像头抓完一轮图片之后就需要等待后续逻辑处理完成
3、双线程
一个线程负责抓图,一个线程负责后续逻辑。抓图线程抓图之后将图片数据放到缓存,分析线程从缓存中获取数据做后续的处理
问题:
- 摄像头抓完一轮图片需要1s多,加上后续的处理,整个时间就有2s多
4、6线程抓图+流程拆分
6个线程抓图。将每个节点拆分:抓图、分析、处理、开关拆分成不同的节点,彼此不等待,独立运行。
- 抓图线程将图片放入缓存
- 分析线程消费缓存数据调用算法进行分析,拿到结果之后放入缓存
- 处理线程消费分析结果,将处理结果放入缓存
- 开关线程消费结果缓存,进行开关灯控制
5、事件总线机制优化流程
还是上述逻辑,只不过通过事件总线去实现,使代码更清晰,更易读。
总体的效果:
- 抓图+压缩:600ms~700ms
- 分析:300ms
- 处理:可忽略不计
- 下发指令:1s以内
现场的体验:2-3s,其中算法识别的快慢对体验影响最大,从算法识别到到开灯在1s以内
六、问题
1、为什么抓图分配6个线程?
服务器是8核8G的,抓图线程会一直占用cpu,线程起太多会导致其他部分的延迟增加
2、为什么往DTU发送的间隔选择1秒
测出来的合理的时间间隔