[英]C++ STL: Array vs Vector: Raw element accessing performance
我正在建立一個翻譯,因為這次我的目標是原始速度,所以在這個(原始)情況下,每個時鍾周期對我都很重要。
您是否有任何經驗或信息兩者更快:Vector或Array? 重要的是我可以訪問元素的速度(操作碼接收),我不關心插入,分配,排序等。
我現在要把自己從窗戶里拉出來說:
這對我來說似乎很合乎邏輯。 使用向量,您可以獲得陣列不存在的所有安全性和控制開銷。
(為什么)我錯了?
不,我不能忽視性能差異 - 即使它是如此之小 - 我已經優化並最小化執行操作碼的VM的每個其他部分:)
std::vector
的典型實現中的元素訪問時間與通過指針對象可用的普通數組中的元素訪問時間相同(即運行時指針值)
std::vector<int> v;
int *pa;
...
v[i];
pa[i];
// Both have the same access time
但是,作為數組對象的數組元素的訪問時間優於上述兩種訪問(相當於通過編譯時指針值進行訪問)
int a[100];
...
a[i];
// Faster than both of the above
例如,通過運行時指針值提供的對int
數組的典型讀訪問將在x86平台上的編譯代碼中如下所示
// pa[i]
mov ecx, pa // read pointer value from memory
mov eax, i
mov <result>, dword ptr [ecx + eax * 4]
對vector元素的訪問看起來幾乎相同。
對可用作數組對象的本地int
數組的典型訪問將如下所示
// a[i]
mov eax, i
mov <result>, dword ptr [esp + <offset constant> + eax * 4]
對作為數組對象提供的全局int
數組的典型訪問將如下所示
// a[i]
mov eax, i
mov <result>, dword ptr [<absolute address constant> + eax * 4]
性能的差異源於第一個變體中的額外mov
指令,它必須進行額外的存儲器訪問。
但是,差異可以忽略不計。 並且它很容易被優化到在多訪問上下文中完全相同的程度(通過在寄存器中加載目標地址)。
因此,當數組可以直接通過數組對象訪問而不是通過指針對象時,關於“數組快一點”的語句是正確的。 但這種差異的實際價值幾乎沒有。
你可能正在咆哮錯誤的樹。 緩存未命中可能比執行的指令數量重要得多。
在引擎蓋下, std::vector
和C ++ 0x std::array
通過向指向第一個元素的指針添加n
來查找指向元素n
的指針。
vector::at
可能比array::at
慢array::at
因為前者必須與變量進行比較,而后者與常量進行比較。 這些是提供邊界檢查的函數,而不是operator[]
。
如果你的意思是C風格的數組 ,而不是的C ++ 0x std::array
,那么有沒有at
成員,但該點保持。
編輯:如果你有一個操作碼表,全局數組(如extern
或static
鏈接)可能會更快。 當常量放在括號內時,全局數組的元素可以作為全局變量單獨尋址,而操作碼通常是常量。
無論如何,這都是過早的優化。 如果你不使用任何vector
的大小調整功能,它看起來就像一個數組,你應該能夠輕松地在兩者之間進行轉換。
你將蘋果與橙子進行比較。 數組具有常量大小並自動分配,而向量具有動態大小並且是動態分配的。 你使用哪個取決於你需要什么。
通常,數組“更快”分配(在引號中因為比較沒有意義),因為動態分配較慢。 但是,訪問元素應該是相同的。 (當然,數組可能更有可能在緩存中,但在第一次訪問后無關緊要。)
另外,我不知道你在說什么“安全性”, vector
有很多方法可以像數組一樣獲得未定義的行為。 雖然它們有at()
,如果你知道索引是有效的,你不需要使用它。
最后,剖析並查看生成的程序集。 沒有人猜測會解決任何問題。
為了獲得不錯的結果,使用std::vector
作為后備存儲,並在主循環或其他之前獲取指向其第一個元素的指針:
std::vector<T> mem_buf;
// stuff
uint8_t *mem=&mem_buf[0];
for(;;) {
switch(mem[pc]) {
// stuff
}
}
這避免了在operator[]
中執行邊界檢查的過度有用的實現的任何問題,並且當在代碼中稍后插入諸如mem_buf[pc]
表達式時使單步執行變得更容易。
如果每條指令都做了足夠的工作,並且代碼變化足夠大,那么這比使用全局數組的速度要快一些。 (如果差異很明顯,則需要使操作碼變得更復雜。)
與使用全局數組相比,在x86上,這種調度的指令應該更簡潔(任何地方都沒有32位位移字段),對於更多類似RISC的目標,應該生成更少的指令(沒有TOC查找或笨拙32 -bit常數),因為常用值都在堆棧幀中。
我並不是真的相信以這種方式優化解釋器的調度循環會產生良好的投入回報 - 如果這是一個問題,那么指令應該真的做得更多 - 但我認為不應該花很長時間嘗試一些不同的方法並衡量差異。 一如往常出現意外行為,應查詢生成的匯編語言(以及x86上的機器代碼,指令長度可能是一個因素),以檢查明顯的低效率。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.