轉 為什麼處理排序的陣列要比非排序的快?

2022-05-20 02:18:47 字數 1789 閱讀 5864

from:

看以下**:

#include #include #include int main()

}double elapsedtime = static_cast(clock() - start) / clocks_per_sec;

std::cout << elapsedtime << std::endl;

std::cout << "sum = " << sum << std::endl;

}

問題就在於,去掉std::sort那一行,以上**將執行更長的時間。在我的機器上未去掉std::sort耗時8.99s,去掉後耗時24.78s。編譯器使用的是gcc4.4.3。事實上,以上**跟編譯器沒有關係,甚至跟語言沒有關係。那這是為什麼呢?

這跟處理這個陣列的邏輯有非常大的關係。如以上**所示,這個迴圈裡有個條件判斷。條件判斷被編譯成二進位制**後,就是乙個跳轉指令,類似:

具體為什麼會不同,這涉及到計算機cpu執行指令時的行為。

想象現在有一堆指令等待cpu去執行,那麼cpu是如何執行的呢?具體的細節可以找一本計算機組成原理的書來看。cpu執行一堆指令時,並不是單純地一條一條取出來執行,而是按照一種流水線的方式,在cpu真正執行一條指令前,這條指令就像工廠裡流水線生產的產品一樣,已經被經過一些處理。簡單來說,一條指令可能經過這些過程:取指(fetch)、解碼(decode)、執行(execute)、放回(write-back)。

假設現在有指令序列abcdefg。當cpu正在執行(execute)指令a時,cpu的其他處理單元(cpu是由若干部件構成的)其實已經預先處理到了指令a後面的指令,例如b可能已經被解碼,c已經被取指。這就是流水線執行,這可以保證cpu高效地執行指令。

如上所說,cpu在執行一堆順序執行的指令時,因為對於執行指令的部件來說,其基本不需要等待,因為諸如取指、解碼這些過程早就被做了。但是,當cpu面臨非順序執行的指令序列時,例如之前提到的跳轉指令,情況會怎樣呢?

取指、解碼這些cpu單元並不知道程式流程會跳轉,只有當cpu執行到跳轉指令本身時,才知道該不該跳轉。所以,取指解碼這些單元就會繼續取跳轉指令之後的指令。當cpu執行到跳轉指令時,如果真的發生了跳轉,那麼之前的預處理(取指、解碼)就白做了。這個時候,cpu得從跳轉目標處臨時取指、解碼,然後才開始執行,這意味著:cpu停了若干個時鐘週期!

這其實是個問題,如果cpu的設計放任這個問題,那麼其速度就很難提公升起來。為此,人們發明了一種技術,稱為branch prediction,也就是分支**。分支**的作用,就是**某個跳轉指令是否會跳轉。而cpu就根據自己的**到目標位址取指令。這樣,即可從一定程度提高執行速度。當然,分支**在實現上有很多方法。

了解了以上資訊後,文章開頭提出的問題就可以解釋了。這個**中有乙個迴圈,這個迴圈裡有乙個條件判斷。每一次cpu執行這個條件判斷時,cpu都可能跳轉到迴圈開始處的指令,即不執行if後的指令。使用分支**技術,當處理已經排序的陣列時,在若干次data[c]>=128都不成立時(或第一次不成立時,取決於分支**的實現),cpu**這個分支是始終會跳轉到迴圈開始的指令時,這個時候cpu將保持有效的執行,不需要重新等待到新的位址取指;同樣,當data[c]>=128條件成立若干次後,cpu也可以**這個分支是不必跳轉的,那麼這個時候cpu也可以保持高效執行。

相反,如果是無序的陣列,cpu的分支**在很大程度上都無法**成功,基本就是50%的**成功概率,這將消耗大量的時間,因為cpu很多時間都會等待取指單元重新取指。

本文完。最後感嘆下stackoverflow上這個帖子裡那個老外回答問題的專業性,我要是樓主早就感動得涕淚橫飛了。感謝每乙個傳播知識的人。

written bykevin lynx posted at

為什麼處理已排序陣列比處理未排序陣列更快?

很久以前在stackoverflow上看到下面這段 今天忍不住把它摘錄過來。include include include int main double elapsedtime static cast clock start clocks per sec std cout elapsedtime ...

IE陣列排序問題的處理

先來簡單的 var k a a 123 k.sort console.log k 結果 123,a,a元素是物件的 var t var tmp new object tmp.id batch add api ticket tmp.val a t.push tmp tmp new object tmp...

演算法 排序 非基於比較的排序

非基於比較的排序與樣本的資料狀況有很大的關係,由於這個限制使其在工程中並不常用。非基於比較的排序有桶排序,基數排序,計數排序。這三者都能做到排序的穩定性,時間複雜度為 o n 空間複雜度為 o n 假設存在一組資料,裡面的資料只有 0 60 使用非基於比較的排序。思路 此時可以使用計數排序,準備 6...