簡體   English   中英

在C ++中使用std :: vector會有什么性能損失?

[英]What is the performance penalty of using std::vector in C++?

通常,我很想知道標准模板庫是否會在數值/科學計算的代碼中產生性能/速度開銷。

例如。 將數組聲明為

double 2dmatrix [10][10]

會給我更多的表現

std::vector<std::vector<double> > 2dmatrix(10,std::vector<double>(10,0.0))

我還要感謝一些一般性的想法,關於C在科學計算方面是否具有比C ++更好的性能。 我使用STL以非常面向對象的方式編寫了我的代碼,並且使用了C ++ 11。 我開始考慮是否應該開始研究純C,如果它運行得更快。

對此有任何想法都是受歡迎的。

鑒於它提供的抽象 ,C ++ std::vector的效率與它一樣高:棧上有3個指針,動態分配的數據在線性增長場景中平均每個元素重新分配1次(因為調整大小擴展了容量更多)比例,1.5至2)。

使用malloc()realloc()的C等價物至少同樣昂貴,而且更麻煩(手動調整大小等)。 此外, std::vector允許通過特殊分配器 (基於池,堆棧分配等)進行用戶定義的性能調優 ,這在C ++ 11中並不像在C ++ 98中那樣難以使用。

如果不需要動態調整大小,可以在C和C ++中編寫靜態數組(或C ++中的std::array )。

通常,對於高性能計算, C ++具有更多的優化潛力 ,特別是通過使用可以內聯的函數對象(與常規C函數指針相比​​)。 規范的例子是排序

int comp( const void* a, const void* b ) {
    return /* your comparison here */;
}

// C style sorting
qsort( arr, LARGE_SIZE, sizeof( int ), comp ); 
                                       ^^^^ <---- no-inlining through function pointer

// C++11 style sorting (use hand-made function object for C++98
std::sort(std::begin(arr), std::end(arr), [](auto a, auto b) { 
    return comp(&a, &b);
           ^^^^ <----- C++11 lambdas can be fully inlined
});

std :: vector的開銷是:

  • 堆棧上有3個指針
  • 動態分配(懶惰,即在需要之前不分配任何東西)

在某些情況下(對於少量數據),堆棧分配的陣列可能更快。 為此,您可以使用std::array<T, Length>

如果你需要一個二維網格,我會在一個向量中分配數據: std::vector<T>(width * height); 然后你可以編寫一些輔助函數來通過x和y坐標獲取元素。 (或者你可以寫一個包裝類 。)

如果您事先知道大小並且性能是瓶頸 - 請使用C ++ 11中的std::array 它的性能與C風格的數組完全相同,因為它內部看起來像

template<typename T, int N>
struct array {
  T _data[N];
};

這是在現代C ++中使用堆棧分配的數組的一種優先方式。 如果您有現代編譯器,切勿使用C風格的數組。

如果您沒有理由調整數組的大小,並且在編譯期間知道它的大小(就像您在第一個示例中所做的那樣),那么STL模板的更好選擇是std::array模板。 它為您提供C風格陣列的所有相同優點。

double 2dmatrix[10][10];

// would become

std::array<std::array<double, 10>, 10> 2dmatrix;

人們會說“這取決於你在做什么”。

他們是對的。

還有一個例子在這里 ,其中使用常規設計的程序std::vector被調諧性能,通過一系列的六個階段,並且其執行時間從每個工作單元2700微秒減少到3.7,為730X的加速因子。

首先要做的是注意到很大一部分時間用於增長數組並從中刪除元素。 因此使用了不同的數組類,這大大減少了時間。

第二件事是注意到很大一部分時間仍然在進行與數組相關的活動。 因此,數組完全被刪除,而使用鏈接列表,產生了另一個大的加速。

然后其他事情使用了大部分剩余時間,例如newdelete對象。 然后這些對象在自由列表中被回收,產生了另一個大的加速。 經過幾個階段之后,我們決定停止嘗試,因為要找到改進的東西變得越來越難,而且加速被認為是足夠的。

關鍵是 ,不要只是選擇一些強烈推薦的東西,然后希望最好。 而是以這種或那種方式構建它,然后像這樣進行性能調整,並願意根據您看到的大部分時間花費在數據結構設計上進行重大更改。 迭代它 您可以將存儲方案從A更改為B,然后從B更改為C.這是完全可以的。

在科學計算中,錯誤和次優代碼特別令人沮喪,因為大量數據被錯誤處理並浪費了寶貴的時間。

std::vector可能是你的瓶頸或你最好的表演者,這取決於你對其內部運作的了解。 要特別注意reserve()insert()erase() ; 如果您的程序是線程化的,請考慮學習對齊和處理器緩存。

如果您嘗試自己完成所有內存管理,尤其是在逐步向軟件添加功能時,請考慮花時間確保一致性以及后來尋找錯誤的時間。 在一天結束時,std :: vector的開銷將是您遇到的最少問題。

對於科學計算,使用專用的C ++矩陣庫(例如Armadillo)會更好。 這不僅可以為您提供快速的陣列處理,還可以進行徹底調試的許多線性代數運算。

除了性能原因之外,使用專用的C ++矩陣庫還可以大大降低代碼的冗長度,減少錯誤,從而加快開發速度。 一個例子是使用C ++矩陣庫,您不必擔心內存管理。

最后,如果你真的需要進入低級別(即直接通過指針使用內存),C ++允許你“下降”到C級別。 在Armadillo中,這是通過.memptr()成員函數完成的。

暫無
暫無

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

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