产生静帧的原因
视频的长度比音频短 ——> 为什么视频短? ——> 1,外部给的数据就少;2,内部合成的问题。
本文主要对7月底出现的一次静帧bug做详细的分析和给出的解决方案。
回顾整个任务流程
- 开始任务:上层服务通知开始做任务时,我根据数据合成最终视频后,通过
Redis
数据库告知上层服务我已经做完任务了。 - 结束任务:上层服务发送结束任务时,我立刻停掉所有正在进行的协程。
问题溯源
首先,我通过看日志发现:上层服务只调用了一次开始任务的请求,但我这里却重复做了任务,也就是一个人做了两次任务。
为什么呢?于是我根据日志查到源头,发现是这个循环检测redis key
出了问题。
1 | var redis_value string |
然而本地测试后发现没问题,那么问题出在哪里呢?
后来我又看了日志,发现两个任务发的时间间隔很短,会不会是任务重了,导致同一个人开了两个协程,协程1在检测协程2已经生成的视频文件,结果视频还没有生成完,就送去做转场合成,导致最终的视频过短,从而产生静帧?
经过和上层服务的负责人沟通,确认他当时发第一次任务后忘记停止任务了,导致发第二次任务时,第一次任务还在循环检测redis key
,最终两个任务一起做了。
于是他改了下代码,重新测试,但是问题还存在,这次主要集中在我这里,因为我发现即使上层服务发送了停止任务的请求,但我这里还是有协程在做检测redis key的活,所以最终问题确认为————发送了停止任务后,我这里没有及时关闭掉协程。
修改代码,使用sync.WaitGroup
控制协程的数量:
person.go
1 | wg := sync.WaitGroup{} //很重要 |
task.go
1 | func Task(stop chan bool,wg *sync.WaitGroup) { |
经过测试,收到停止任务后即可结束正在做任务的协程。
个人理解的sync.WaitGroup的用法
专业解释可以看官方文档或文章底部的参考资料,在此仅仅对我目前所用的WaitGroup
做简单的理解,如有误差请及时提出来我好补充,感谢。
WaitGroup
就像是一个计数器,开一个协程,Add
就会让计数器加1,当协程运行完或中间退出时,Done
就会减1,但当你开了很多协程,但又不知道什么时候协程会全部结束时,就需要Wait
等待所有协程结束。
而对于一些必须要及时退出协程的情况(比如我上述锁描述的情况),就需要用channel
通知协程关闭,所以一定要在所有协程可能会退出的情况记得Done
,或者使用defer wg.Done
,否则WaitGroup
这个“计数器”不为1,它就会一直卡住。
总结
- 遇到问题多想,多测试,多看日志,多分析;
- 实在找不到问题,可以和相关的负责人员沟通,一起寻找突破口;
- 一定要找到问题的本质,从根源解决,不要想着用一个应急方案先凑活,不然你会发现你的职业生涯就一直在和这类业务问题做斗争;
sync.WaitGroup
是让协程优雅退出的一种解决方式,那么是否还有其他让协程退出的方法呢?- 所有看似匪夷所思的
Bug
,背后一定绕不开它的基础原理; - 最后感谢部门同事@yangfengyu和@chenhan的帮助,让我有
get
了一个新技能。
参考资料
简书_Golang并发:并发协程的优雅退出
你真的会用sync.WaitGroup吗
起风了_Golang等待组sync.WaitGroup的用法