繁体   English   中英

当Python中的主线程cpu负载很重时,防止在后台线程上丢失UDP数据包

[英]Prevent UDP packet loss on background thread when main thread cpu load is heavy in Python

我正在研究一个原型应用程序,主要是用Python(2.7)编写的一个研究项目。 该应用程序通过UDP从无线设备接收mpegts视频流,然后使用openCV处理/分析视频帧。 mpeg解压缩是在我自己的C库中完成的,该库基本上只是libavcodec的Python绑定包装器。 该应用程序是一个Python GLUT应用程序,它使用GLUT进行绘制和基本的一些事件处理。

我的问题是,当我的openCV处理或绘图代码使CPU负担时,我会丢弃UDP数据包,从而导致视频帧损坏。 我知道UDP是一种“不可靠”的协议,并且可能会丢失数据包,但是很遗憾,这是我必须使用的协议。

幸运的是,我有一台运行速度非常快的计算机(MacBookPro11,3 2.8GHz四核i7)。 我的目标是创建一个使用线程和队列的系统,从而优先考虑UDP数据包的使用和视频解压缩,以便完整接收每个解压缩的帧(除非出现实际的网络错误)。 如果我的主线程绘图或处理无法跟上视频流的帧速率,我想丢弃整个解压缩的帧,以使mpeg流保持连贯。 另一种方法是丢弃单个UDP数据包,但这会导致图像流损坏,该图像流在一段时间内即无法恢复。 我相信下一个I帧的接收。 这是我要避免的情况。

我已经创建了一个产生后台线程的系统,该系统负责创建视频解压缩上下文和UDP套接字的所有工作。 后台线程无限循环,向解压缩器询问解码的帧,然后依次调用必要的回调,该回调等待来自套接字的更多数据(使用select,poll或block recv,我已经尝试了全部三个)。 接收到每个新的解压缩帧后,后台线程将这些帧添加到队列中,并在队列中以最快的速度处理这些帧。 如果由于主线程使用者无法跟上队列而使队列已满,那么刚刚解压缩的新帧将被丢弃,并且过程将继续。

我遇到的问题是,即使使用此系统,主线程上的沉重负担仍然会导致UDP数据包被丢弃。 几乎就像接收和缓冲传入udp数据包的内核数据包调度程序在我的主线程上运行一样,该线程正在完成视频帧的所有绘制和处理(我只有一半知道我在说什么,例如。数据包调度程序)。 如果我注释掉在主线程上运行的所有繁重的处理和绘图代码,那么我将永远不会遇到任何丢包/ mpeg解码错误。

我已经尝试过最大化套接字接收缓冲区,这虽然有所帮助,但是也会增加延迟,这也是不希望的,并且最终只会延迟问题。

所以我的问题是,我该怎么做以确保我的所有UDP数据包都被消耗并尽可能快地传递给解压缩器,而与主线程cpu负载无关?

我尝试将后台线程的线程优先级设置为1.0,但这无济于事。 默认情况下,libavcodec会生成9个线程来处理解压缩,但我可以选择将其限制为1(我尝试过将其限制为1),以确保所有解压缩都发生在同一(高优先级)线程上。 看着我的cpu监视器,我的四核处理器(带有超线程的8个处理器,我也尝试过打开和关闭)有很多开销。

如有必要,我很乐意将内核调整为root,因为这只是一个研究项目,而不是运输应用程序。

有什么建议吗?

TIA

Python不直接支持设置线程优先级,但是有些人很幸运使用ctypes来做到这一点。 但是,由于GIL的工作方式,无论如何,它可能不会给您带来最佳效果。

最好的办法可能是使用多重处理将UDP线程放置在单独的进程中,并使用队列将视频从该进程传输到您的主进程。

为了避免死锁,您应该在启动任何线程之前启动UDP进程(启动线程运行后启动进程是有问题的,因为线程和IPC状态没有正确复制到子进程中),然后,在启动UDP进程之后,您应该降低主进程在启动其中的任何线程之前的优先级

这是一篇有趣的论文 ,它不是直接提出来的,而是提供了一些有关Python(不幸的是3)和线程优先级的信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM