简体   繁体   English

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

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

I'm working on a prototype application, primarily written in Python (2.7) for a research project. 我正在研究一个原型应用程序,主要是用Python(2.7)编写的一个研究项目。 The application receives an mpegts video stream from a wireless device over UDP and then uses openCV to process/analyze the video frames. 该应用程序通过UDP从无线设备接收mpegts视频流,然后使用openCV处理/分析视频帧。 The mpeg decompression is done in my own C library which is basically just a Python bound wrapper around libavcodec. mpeg解压缩是在我自己的C库中完成的,该库基本上只是libavcodec的Python绑定包装器。 The application is a Python GLUT app which uses GLUT for the drawing and basic some event handling. 该应用程序是一个Python GLUT应用程序,它使用GLUT进行绘制和基本的一些事件处理。

My problem is that when my openCV processing or drawing code taxes the CPU I get dropped UDP packets resulting in corrupted video frames. 我的问题是,当我的openCV处理或绘图代码使CPU负担时,我会丢弃UDP数据包,从而导致视频帧损坏。 I know that UDP is an 'unreliable' protocol and that dropped packets are to be expected but unfortunately it's what I have to work with. 我知道UDP是一种“不可靠”的协议,并且可能会丢失数据包,但是很遗憾,这是我必须使用的协议。

Fortunately I have a decently fast machine that I'm running this on (MacBookPro11,3 2.8GHz quad core i7). 幸运的是,我有一台运行速度非常快的计算机(MacBookPro11,3 2.8GHz四核i7)。 My aim is to create a system using threads and queues whereby the consumption of UDP packets and video decompression is prioritized, so that every decompressed frame is received intact (barring actual network errors). 我的目标是创建一个使用线程和队列的系统,从而优先考虑UDP数据包的使用和视频解压缩,以便完整接收每个解压缩的帧(除非出现实际的网络错误)。 If my main thread drawing or processing is unable to keep up with the video stream frame rate I'd like to drop entire decompressed frames so that the mpeg stream remains coherent. 如果我的主线程绘图或处理无法跟上视频流的帧速率,我想丢弃整个解压缩的帧,以使mpeg流保持连贯。 The alternative is to have individual UDP packets dropped, but this results in a corrupted image stream which is not restored for some period of time, ie. 另一种方法是丢弃单个UDP数据包,但这会导致图像流损坏,该图像流在一段时间内即无法恢复。 the receipt of the next I-frame, I believe. 我相信下一个I帧的接收。 This is the situation that I'm trying to avoid. 这是我要避免的情况。

I've already created such a system whereby a background thread is spawned, which does all of the work of creating the video decompression context and UDP socket. 我已经创建了一个产生后台线程的系统,该系统负责创建视频解压缩上下文和UDP套接字的所有工作。 The background thread loops infinitely asking the decompressor for decoded frames which in turn calls a callback as necessary which which waits on more data from the socket (either using select, poll or blocking recv, I've tried all three). 后台线程无限循环,向解压缩器询问解码的帧,然后依次调用必要的回调,该回调等待来自套接字的更多数据(使用select,poll或block recv,我已经尝试了全部三个)。 Upon the receipt of each new decompressed frame, the background thread adds the frames to a queue, which are consumed on the main thread as fast as it can handle. 接收到每个新的解压缩帧后,后台线程将这些帧添加到队列中,并在队列中以最快的速度处理这些帧。 If the queue is full because the main thread consumer can't keep up, then the newly decompressed frame just gets discarded and the process continues. 如果由于主线程使用者无法跟上队列而使队列已满,那么刚刚解压缩的新帧将被丢弃,并且过程将继续。

The problem that I'm having is that even using this system, a heavy load on the main thread is still causing UDP packets to be dropped. 我遇到的问题是,即使使用此系统,主线程上的沉重负担仍然会导致UDP数据包被丢弃。 It's almost as if the kernel packet scheduler which receives and buffers the incoming udp packets is running on my main thread, which is doing all of the drawing and processing of video frames (I only half know what I'm talking about here, re. packet scheduler). 几乎就像接收和缓冲传入udp数据包的内核数据包调度程序在我的主线程上运行一样,该线程正在完成视频帧的所有绘制和处理(我只有一半知道我在说什么,例如。数据包调度程序)。 If I comment out all of the heavy processing and drawing code running on the main thread then I never get any dropped packets / mpeg decode errors. 如果我注释掉在主线程上运行的所有繁重的处理和绘图代码,那么我将永远不会遇到任何丢包/ mpeg解码错误。

I've already tried maxing out my socket receive buffer which helps somewhat but that also increases latency, which is also undesirable, and it ultimately just delays the problem. 我已经尝试过最大化套接字接收缓冲区,这虽然有所帮助,但是也会增加延迟,这也是不希望的,并且最终只会延迟问题。

So my question is, what can I do to ensure that all of my UDP packets are being consumed and passed to the decompressor as rapidly as possible, independent of the main thread cpu load? 所以我的问题是,我该怎么做以确保我的所有UDP数据包都被消耗并尽可能快地传递给解压缩器,而与主线程cpu负载无关?

I've tried setting the background thread's thread priority to 1.0 but that doesn't help. 我尝试将后台线程的线程优先级设置为1.0,但这无济于事。 libavcodec by default is spawning 9 threads to handle the decompression, but I can optionally restrict it to 1, which I've tried, to ensure that all of the decompression happens on the same (high priority) thread. 默认情况下,libavcodec会生成9个线程来处理解压缩,但我可以选择将其限制为1(我尝试过将其限制为1),以确保所有解压缩都发生在同一(高优先级)线程上。 Looking at my cpu monitor I've got tons of overhead on my quad core processor (8 with hyperthreading, which I've tried turning on and off too). 看着我的cpu监视器,我的四核处理器(带有超线程的8个处理器,我也尝试过打开和关闭)有很多开销。

I'd be happy to make kernel tweaks as root if necessary, as this is just a research project and not a shipping application. 如有必要,我很乐意将内核调整为root,因为这只是一个研究项目,而不是运输应用程序。

Any advice? 有什么建议吗?

TIA TIA

Python doesn't directly support setting thread priorities, but some people have had luck doing that with ctypes. Python不直接支持设置线程优先级,但是有些人很幸运使用ctypes来做到这一点。 BUT, due to the way the GIL works, that probably won't give you the best results anyway. 但是,由于GIL的工作方式,无论如何,它可能不会给您带来最佳效果。

The best thing to do is probably to use multiprocessing to to place your UDP thread in a separate process, and use a queue to transport the video from that process to your main process. 最好的办法可能是使用多重处理将UDP线程放置在单独的进程中,并使用队列将视频从该进程传输到您的主进程。

To avoid deadlocks, you should start the UDP process before starting any threads (starting processes after starting threads running is problematic because the thread and IPC state is not copied properly to the subprocesses), and then, after starting the UDP process, you should lower the priority of the main process before starting any threads in it. 为了避免死锁,您应该在启动任何线程之前启动UDP进程(启动线程运行后启动进程是有问题的,因为线程和IPC状态没有正确复制到子进程中),然后,在启动UDP进程之后,您应该降低主进程在启动其中的任何线程之前的优先级

Here is an interesting paper that is not directly on-point, but gives some good information on Python (3, unfortunately) and thread priorities. 这是一篇有趣的论文 ,它不是直接提出来的,而是提供了一些有关Python(不幸的是3)和线程优先级的信息。

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

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