簡體   English   中英

在 OpenCV 中訪問具有多個線程的 Mat 是否是線程安全的?

[英]Is it thread-safe to access a Mat with multiple threads in OpenCV?

我想加速一個算法(完整的本地二進制模式與圓形鄰居),我遍歷所有像素並用它的鄰居計算一些東西(所以我需要鄰居像素訪問)。

目前我通過用一個線程/進程迭代所有像素來做到這一點。 我想通過將輸入圖像分成多個 ROI 並單獨計算每個 ROI(使用多個線程)來並行化此任務。

這里的問題是,ROI 是重疊的(因為要計算一個像素,有時我需要看遠處的鄰居),並且多個線程可能同時訪問像素數據( READING )。 如果兩個或多個線程同時在相同的索引上讀取相同的 Mat,這是一個問題嗎?

如果我寫入相同的 Mat 並行但使用不同的索引,這也是一個問題嗎?

通常,並行讀取不是問題,因為cv::Mat只是一個很好的數組包裝器,就像std::vector (是的,存在差異,但我看不出它們會如何影響此處的主題所以我將忽略它們)。 然而,並行化不會自動為您帶來性能提升。 這里有很多事情需要考慮:

創建線程需要大量資源,如果任務相對較短(就計算時間而言)可能會產生很大的負面影響,因此必須考慮線程池。

如果您編寫高性能代碼(無論是多線程還是單線程),您應該了解您的硬件是如何工作的。 在這種情況下:內存和 CPU。 Timur Doumler 在 CppCon 2016 上有一個關於這個話題的非常好的演講 這應該可以幫助您避免緩存未命中。

另外值得一提的是編譯器優化。 打開它。 我知道這聽起來非常明顯,但是 SO 上有很多人詢問有關性能的問題,但他們不知道編譯器優化是什么。

最后,還有 OpenCV Transparent API (TAPI),它基本上使用 GPU 而不是 CPU。 幾乎所有 OpenCV 的內置算法都支持 TAPI,你只需要傳遞一個cv::UMat而不是cv::Mat 這兩種類型可以相互轉換。 但是,轉換很耗時,因為UMat基本上是 GPU 內存 (VRAM) 上的一個數組,這意味着每次轉換時都必須復制它。 訪問 VRAM 也比訪問 RAM 花費的時間更長(對於 CPU 而言)。 但是,您必須記住,如果不將 VRAM 數據復制到 RAM,就無法使用 CPU 訪問 VRAM 數據。 這意味着如果您使用cv::UMat則無法迭代像素。 只有編寫自己的 OpenCL 或 Cuda 代碼才能在 GPU 上運行算法。

在大多數消費級 PC 中,對於滑動窗口算法(基本上是迭代像素並圍繞每個像素執行計算的任何算法),使用 GPU 通常是迄今為止最快的方法(但也需要最大的努力來實現)。 當然,這只適用於數據緩沖區(您的圖像)足夠大以使其值得復制到 VRAM 或從 VRAM 復制的情況下。

對於並行寫入:只要您沒有重疊區域,它通常是安全的。 然而,緩存未命中和錯誤共享(如 NathanOliver 所指出的)是需要考慮的問題。

只要讀操作沒有同時發生寫操作,多個並發讀操作是安全的。

這適用於任何健全的系統。

考慮替代方案:

如果存在競爭條件,則意味着存儲對象的內存在讀取操作期間被修改。 如果在讀取期間沒有寫入內存(存儲對象),則線程之間不可能進行交互。

最后,如果您查看文檔,

https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html

你會看到兩次提到線程安全:

因此,在不同線程中異步操作相同的矩陣是安全的。

他們提到在矩陣分配期間執行的引用計數。 因此,至少可以在多個線程中安全地從同一個矩陣分配給另外兩個矩陣。 這幾乎保證了簡單的讀取訪問也是線程安全的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM