簡體   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