在開發中你可能沒有考慮到的兩個性能優化


1:多余的存儲引用導致性能降低;

2:利用局部性提高程序性能;

先來說說引用是怎么降低程序性能,個人認為降低程序性能主要有兩個原因,一是數據結構選擇不合理,二是多層嵌套循環導致部分代碼被多余重復執行。在第二種情況下我們一般都是優化循環最里層的代碼,能提出來的盡量往外層提,實在不行的就優化它的運行速度。

1:多余的存儲引用導致性能降低。先來看一個關於引用導致性能降低的問題。下面兩個方法哪個更快。

        static void Test2(ref int sum)
        {
            for (int i = 1; i <= timer; i++)
            {
                sum += i;
            }
        }

        static void Test3(ref int sum)
        {
            int tmpSum = sum;
            for (int i = 1; i <= timer; i++)
            {
                tmpSum += i;
            }
            sum = tmpSum;
        }

大致一看他們的性能應該沒有差別,因為這兩個方法其實就是利用一個循環求和,而真正能影響方法的性能就是這個循環,且兩個方法的循環表面上看可以說是一樣的,當,我令timer=10000000時,即求1+2+...+10000000的和,方法Test3的速度比Test2快。是的,Test3比Test2快,在某個區間內timer越大,性能差別越大。運行結構如下:

咱們直接來看反匯編代碼,部分反匯編代碼如下,我們只用看紅線框着的部分。

 

最主要的一句代碼:sum+=i;方法Test2比方法Test3多了最后面一行,即將每次循環后求得的和回寫到內存中,方法Test3卻不用這么麻煩,只用一個寄存器,每次求得的和寫到寄存器中,求完和后一次將和寫到內存中。在每次循環中,Test2要讀兩次內存(sum和i都從內存中讀),寫一次內存(將求得的和寫到內存中),而方法Test3只需要讀一次內存,即從內存中讀i的值,方法Test3的性能比Test2高就不言而喻了。就因為Test2每次都是以引用的方式讀sum的值,CPU要得到sum的值,就得通過sum在內存中的地址,所以必讀內存,,而Test3不必讀內存,用一個寄存器即可。

 

2:利用局部性提高程序性能。還是直接看一個簡單的例子

        static int Test4(int[,] arr, int row, int column)
        {
            int sum = 0;
            for (int i = 0; i < row; i++)
            {
                for (int j = 0; j < column; j++)
                {
                    sum += arr[i, j];
                }
            }
            return sum;
        }

        static int Test5(int[,] arr, int row, int column)
        {
            int sum = 0;
            for (int j = 0; j < column; j++)
            {
                for (int i = 0; i < row; i++)
                {
                    sum += arr[i, j];
                }
            }
            return sum;
        }

簡單一個看,兩個方法幾乎是完全一樣,不同的是Test4是按行求和,而Test5是按列求和。如果多次執行這兩個方法進行,對比就會方法Test4的性能高於Test5。運行兩個方法100000次,結果如下:

為什么按行求和比按列求和快呢?簡單一句話:數組是按行存的。CPU每次從內存讀數據,不是要哪個就讀哪個就直接讀哪個,而是每次讀一個高速緩存行,就是每次要多讀一些,如,果需要的數據在高速緩存行中,就不用到內存中去讀了,而是直接從高速緩存行中取,當然就比再從內存中讀取要快一些。而在這里,數組按行存儲,也就是說,CPU每次會讀多個數組元素導高速緩存行,如果需要的元素在高速緩存行中就不用到內存中去取了,這就是傳說中的命中率,按行求和命中率當然就高了。而按列求和,命中率自然低,CPU每次將一行中的多個元素讀到高速緩存行中,按列求和每次只需要一個元素,也就是每次只需要一個元素而CPU卻讀了多個元素,命中率當然低,低到可能出現命中率為0。

程序的局部性包括:空間局部性和時間局部性,這里說的就是空間局部性。

空間局部性就是說一個被使用的到數據其周圍的數據很可能會被馬上使用。

時間局部性就是說一個被使用的到數據很可能會被再次使用。

更多內容請看《深入理解操作系統》。

作者:陳太漢

博客:http://www.cnblogs.com/hlxs/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM