1. 程式人生 > >陣列排序前後的執行效率區別

陣列排序前後的執行效率區別

有如下程式碼:

import java.util.Arrays;
import java.util.Random;

public class Main
{
    public static void main(String[] args)
    {
        // Generate data
        int arraySize = 32768;
        int data[] = new int[arraySize];

        Random rnd = new Random(0);
        for (int c = 0; c < arraySize; ++c)
            data[c] = rnd.nextInt() % 256;

        // !!! With this, the next loop runs faster
        <strong>Arrays.sort(data);</strong>

        // Test
        long start = System.nanoTime();
        long sum = 0;

        for (int i = 0; i < 100000; ++i)
        {
            // Primary loop
            for (int c = 0; c < arraySize; ++c)
            {
<span style="color:#ff0000;">               </span><strong style="color: rgb(255, 0, 0);"> if (data[c] >= 128)</strong><span style="color:#ff0000;">
                  </span><strong><span style="color:#ff0000;">  </span>sum += data[c];</strong>
            }
        }

        System.out.println((System.nanoTime() - start) / 1000000000.0);
        System.out.println("sum = " + sum);
    }
}

排序後的陣列,執行效率與未排序時有明顯區別,我本地執行時,前者是5s,後者為11s。

這是一個典型的“分支預測”問題。

假設你是18世紀的扳道工,這時遠端通訊技術並不發達。你並不知道每輛火車的方向,所以每當火車遇到岔道口,需要先停下來告知駛向的方向並進行調整,然後才可以啟動。笨重的火車具有很大的慣性,所以需要頻繁的停下啟動。

有什麼好的方法?你來預測火車前進的方向!

1.預測成功,火車直接前進即可。

2.預測失敗,停下、換道、重啟。

如果你每次都預測成功了,那麼火車中途就不需要停頓了。

然而你經常預測失敗,所以大量的時間被耗費在剎車、重啟上。。

在處理器級別,if是典型的分支預測指令。


當程式在處理器中執行時,只有走到那一步才知道判斷的結果,現代的處理器結構複雜,所以經常需要剎車、重啟。

有更好的方法麼?處理器來預測分支的走向!

1.預測成功,繼續執行。

2.預測失敗,回滾、重新執行。

如果處理器每次都預測成功,那麼處理器不會回滾。

然而處理器經常預測失敗,所以耗費了大量的時間在回滾上。

這就是所謂的“分支預測”,可能這個比喻並不是十分的貼切——火車可以在車頭高高的插一面旗幟表示方向,但是在處理器中,直到最後一刻處理器才會知道執行的方向。

處理器如何才能最少化回滾的次數呢?——以史為鏡。如果前面99次火車都是朝左開,那麼第一百次也會選擇左邊;如果是輪流的,那麼下一次跟前一次就是相反的;如果每三次改變方向,同上。。。

簡而言之,處理器試圖總結一個模型,並遵循這個模型。

大部分的應用程式執行時都很有規律,領先的分支預測模型甚至能夠達到90%以上的命中率,但是遇到難以預測的隨機情況,分支預測機制也無能為力。

回頭看上面的程式,可知造成效率差異的罪魁禍首是那個if判斷,在預先沒有對陣列進行排序時,分支預測失效,導致處理器頻繁的rollback;而在排序後,處理器很容易就找到了適用的預測模型,大大提高了效率。

解決方案:

1.在if語句之前加上排序。

2.避免分支預測,即使用位運算來替代if語句(犧牲可讀性):

if (data[c] >= 128)
    sum += data[c];
改為
int t = (data[c] - 128) >> 31;
sum += ~t & data[c];
即可。注意:如上程式碼並不適用所有環境。

驗證結果穩定在5.8s。

相關推薦

陣列排序前後執行效率區別

有如下程式碼: import java.util.Arrays; import java.util.Random; public class Main { public static void main(String[] args) {

innerjoin 和 exists的執行效率區別

今天在實現業務時發現經常使用exists語句竟然執行效率低下根本不出結果,反而innerjoin可以瞬間得到結果。後來發現是因為exsits需要從40萬的資料集中去匹配200條資料是非常消耗資源的。總結:首先要確定資料分佈情況,高命中的情況下使用exists的效率要比innerjoin的高,低命中率的情況下還

三個基本排序演算法執行效率比較(氣泡排序,選擇排序和插入排序

1、冒泡演算法。 冒泡演算法是最基礎的一個排序演算法,每次使用第一個值和身後相鄰的值進行比較,如果是升序將大數向左邊交換,降序則向右邊交換。最終將大數移動到一邊,最終排成一個序列: public class Sorting { public void Bubble

java排序演算法-比較快速排序,氣泡排序,雙向氣泡排序執行效率

快速排序 原理是找出一個元素(理論上可以隨便找一個)作為基準(pivot),然後對陣列進行分割槽操作,使基準左邊元素的值都不大於基準值,基準右邊的元素值 都不小於基準值,如此作為基準的元素調整到排序後的正確位置。遞迴快速排序,將其他n-1個元素也調整到排序後的正確位置。

select count(*)、count(1)、count(0)的區別執行效率比較

rst 區別 如果 定性 count(0 決定性 計算 fir 執行 區別 執行效率比較 執行效率從高到低 count(*)=count(1)=count(0)>count(colFirst)>count(colLast) 1.由於count(*)的算法

MySQL count(*)、count(1)、count(column)的區別執行效率比較

count(*)、count(1)、count(column)區別     count(column) 會忽略為 null 的列,其他兩個不會。 執行效率     它們三個的效率如何呢?網上說的各

javaSE (二十八)異常的兩個分類、final、finally、finalize的區別、return在finally前後執行問題、異常練習題

1、異常的兩個分類: 編譯時異常: 在編譯某個程式時,有可能會發生的事情,比如檔案找不到,這樣的異常必須在編譯的時候處理,如果不處理編譯通不過 執行時異常: 就是程式設計師犯的錯誤,需要回來修改程式碼 2、final、finally、finalize的區別: final:修飾類不

快速排序效率較高的陣列排序方式)

實現快速排序的關鍵在於,你從一個數組中取出了一個數字,將他和陣列中所有的數字相比較,比他小的放在陣列的最左邊,比他大的放在最右邊,這個數字將陣列分成比他大和比他小的倆部分,同樣的道理,被分成的倆個子陣列,又可以隨機找出一個數字尋找比他大和小的,一個到最後子陣列沒

對比一下陣列排序演算法效率

package {         import flash.display.Sprite;         import flash.utils.getTimer;         /**          * 測試排序效率          * @author pelephone          */ 

Select count(*)和Count(1)的區別執行效率比較

 在MySQL中Count(*)或者Count(1)或者Count([列])或許是最常用的聚合函式。很多人其實對這三者之間是區分不清的。經常會看到一些所謂的優化建議不使用Count(* )而是使用Count(1),從而可以提升效能,給出的理由是Count( *)會帶來全表

陣列排序效率

工作上碰到的一個問題,關係快排效率。為了簡化問題,我把排序限定為整型陣列,按照升序初始化,快排為降序。最開始的資料量為100萬,發現一秒都不到。然後擴大到1000萬,一億分別是:1000萬6秒,1億77秒。debug版本,i3-2120 3.3GHz,3GRAM

優美的講解String、StringBuffer和StringBuilder的區別執行效率

在大部分情況下 StringBuffer > StringStringBufferJava.lang.StringBuffer執行緒安全的可變字元序列。一個類似於 String 的字串緩衝區,但不能修改。雖然在任意時間點上它都包含某種特定的字元序列,但通過某些方法呼叫可以改變該序列的長度和內容。可將字串

C#監控代碼執行效率

light 運行時 測量 pan 獲取 min mes csharp stopwatch System.Diagnostics.Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // 開始監視代碼運行時間

五十個小技巧提高PHP執行效率(一)

雙引號 超時 而不是 也會 per 遠程 設置 作用 我們 在項目開發過程中,經常遇到了一些PHP處理程序性能底下的情況,程序運行在centos+nginx環境,雖然這個有很多的原因如:服務器本身配置,運行環境nginx服務,php-fpm配置等等,更多有一點仍然是PHPe

50個技巧提高你的PHP網站程序執行效率

運用 絕對路徑 顯示 ase each follow 程序 zend feof 1、用單引號代替雙引號來包含字符串,這樣做會更快一些。因為PHP手冊中說echo是語言結構,不是真正的函數,故 把函數加上了雙引號)。 2、如果能將類的方法定義成static,就盡量定義成sta

寫一個函數計算但參數為n(n很大)時的值1-2+3-4+5-6+7……+n。(考慮程序執行效率

參數 color n) col sys class n-1 == code 1 private static void jisuan(int n) { 2 int sum=0; 3 if(n%2==0){ 4 sum=-(n/2)

使用Android的硬件縮放技術優化執行效率

net opengl quest face 研究 roi ace 技術 https Unity3D研究院之使用Android的硬件縮放技術優化執行效率 http://www.xuanyusong.com/archives/3205 Android中GLSurfaceView

MySQL查看SQL語句執行效率

博客 union pan art 顯示 uniq left join 匹配 article Explain命令在解決數據庫性能上是第一推薦使用命令,大部分的性能問題可以通過此命令來簡單的解決,Explain可以用來查看 SQL 語句的執行效 果,可以幫助選擇更好的索引和優化

SQL Server 並行操作優化,避免並行操作被抑制而影響SQL的執行效率

情況 無法 ima rom 謝謝 tro 開啟 導致 edate 為什麽我也要說SQL Server的並行: 這幾天園子裏寫關於SQL Server並行的文章很多,不管怎麽樣,都讓人對並行操作有了更深刻的認識。 我想說的是:盡管並行操作可能(並不是一定)存

ArrayList 和 LinkedList的執行效率比較

bst 輸出 快捷 iteration sting 遍歷 面向對象 循環 集合 一、概念: 一般我們都知道ArrayList* 由一個數組後推得到的 List。作為一個常規用途的對象容器使用,用於替換原先的 Vector。允許我們快速訪問元素,但在從列表中部插入和刪