国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

為什么處理已排序的數(shù)組比處理未排序的數(shù)組更快?

在此 C++ 代碼中,對(duì)數(shù)據(jù)進(jìn)行排序(在定時(shí)區(qū)域之前)使主循環(huán)速度加快約 6 倍:

#include <algorithm>#include <ctime>#include <iostream>int main(){
    // Generate data
    const unsigned arraySize = 32768;
    int data[arraySize];
    for (unsigned c = 0; c < arraySize; ++c)
        data[c] = std::rand() % 256;
    // !!! With this, the next loop runs faster.
    std::sort(data, data + arraySize);
    // Test
    clock_t start = clock();
    long long sum = 0;
    for (unsigned i = 0; i < 100000; ++i)
    {
        for (unsigned c = 0; c < arraySize; ++c)
        {   // Primary loop.
            if (data[c] >= 128)
                sum += data[c];
        }
    }
    double elapsedTime = static_cast<double>(clock()-start) / CLOCKS_PER_SEC;
    std::cout << elapsedTime << '\n';
    std::cout << "sum = " << sum << '\n';}


文章來(lái)源地址http://www.zghlxwxcb.cn/article/276.html

  • 如果沒(méi)有std::sort(data, data + arraySize);,代碼運(yùn)行時(shí)間為 11.54 秒。

  • 使用排序后的數(shù)據(jù),代碼運(yùn)行時(shí)間為 1.93 秒。

(排序本身比遍歷數(shù)組需要更多時(shí)間,因此如果我們需要為未知數(shù)組計(jì)算排序,那么實(shí)際上不值得這樣做。)


最初,我認(rèn)為這可能只是一種語(yǔ)言或編譯器異常,所以我嘗試了Java:

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
        Arrays.sort(data);
        // Test
        long start = System.nanoTime();
        long sum = 0;
        for (int i = 0; i < 100000; ++i)
        {
            for (int c = 0; c < arraySize; ++c)
            {   // Primary loop.
                if (data[c] >= 128)
                    sum += data[c];
            }
        }
        System.out.println((System.nanoTime() - start) / 1000000000.0);
        System.out.println("sum = " + sum);
    }}

具有類(lèi)似但不那么極端的結(jié)果。



我的第一個(gè)想法是排序?qū)?shù)據(jù)帶入緩存,但這很愚蠢,因?yàn)閿?shù)組剛剛生成。

  • 到底是怎么回事?

  • 為什么處理已排序的數(shù)組比處理未排序的數(shù)組更快?

該代碼總結(jié)了一些獨(dú)立的術(shù)語(yǔ),因此順序并不重要。


什么是分支預(yù)測(cè)?


考慮一個(gè)鐵路樞紐:

現(xiàn)在為了便于討論,假設(shè)現(xiàn)在是 1800 年代——遠(yuǎn)距離或無(wú)線電通信出現(xiàn)之前。

你是路口的盲人操作員,你聽(tīng)到火車(chē)駛來(lái)。你不知道它應(yīng)該走哪條路。你停下火車(chē)詢問(wèn)司機(jī)他們想要哪個(gè)方向。然后你適當(dāng)?shù)卦O(shè)置開(kāi)關(guān)。

火車(chē)很重并且有很大的慣性,因此它們需要很長(zhǎng)時(shí)間才能啟動(dòng)和減速。

有沒(méi)有更好的辦法?你猜火車(chē)會(huì)開(kāi)往哪個(gè)方向!


  • 如果你猜對(duì)了,就繼續(xù)。

  • 如果你猜錯(cuò)了,船長(zhǎng)會(huì)停下來(lái),后退,并對(duì)你大喊,要求你打開(kāi)開(kāi)關(guān)。然后它可以沿著另一條路徑重新啟動(dòng)。

如果你每次都猜對(duì)了,火車(chē)就永遠(yuǎn)不會(huì)停下來(lái)。
如果您經(jīng)常猜錯(cuò),火車(chē)將花費(fèi)大量時(shí)間停車(chē)、倒車(chē)和重新啟動(dòng)。


考慮一個(gè) if 語(yǔ)句:在處理器級(jí)別,它是一條分支指令:

pyfwC.png

你是一個(gè)處理器,你看到一個(gè)分支。你不知道它會(huì)走向何方。你做什么工作?您停止執(zhí)行并等待前面的指令完成。然后你繼續(xù)沿著正確的道路前進(jìn)。

現(xiàn)代處理器很復(fù)雜并且管道很長(zhǎng)。這意味著他們需要永遠(yuǎn)“熱身”和“放慢速度”。

有沒(méi)有更好的辦法?你猜分支會(huì)走向哪個(gè)方向!

  • 如果你猜對(duì)了,你就繼續(xù)執(zhí)行。

  • 如果你猜錯(cuò)了,你需要刷新管道并回滾到分支。然后您可以沿著另一條路徑重新啟動(dòng)。

如果你每次都猜對(duì)了,執(zhí)行就永遠(yuǎn)不必停止。
如果你經(jīng)常猜錯(cuò),你就會(huì)花費(fèi)大量時(shí)間停頓、回滾和重新啟動(dòng)。


這就是分支預(yù)測(cè)。我承認(rèn)這不是最好的類(lèi)比,因?yàn)榛疖?chē)可以用旗幟來(lái)指示方向。但在計(jì)算機(jī)中,處理器直到最后一刻才知道分支將走向哪個(gè)方向。

您如何從策略上猜測(cè)以盡量減少火車(chē)必須倒車(chē)并沿另一條路線行駛的次數(shù)?你看看過(guò)去的歷史吧!如果火車(chē) 99% 的時(shí)間都是向左行駛,那么你猜是向左行駛。如果它交替,那么你就會(huì)改變你的猜測(cè)。如果每三次走一個(gè)方向,你猜的都是一樣的......

換句話說(shuō),你嘗試識(shí)別一種模式并遵循它。這或多或少就是分支預(yù)測(cè)器的工作原理。

大多數(shù)應(yīng)用程序都有行為良好的分支。因此,現(xiàn)代分支預(yù)測(cè)器通常會(huì)實(shí)現(xiàn) >90% 的命中率。但是,當(dāng)面對(duì)沒(méi)有可識(shí)別模式的不可預(yù)測(cè)的分支時(shí),分支預(yù)測(cè)器實(shí)際上毫無(wú)用處。


正如上面所暗示的,罪魁禍?zhǔn)资沁@個(gè) if 語(yǔ)句:

if (data[c] >= 128)
    sum += data[c];

請(qǐng)注意,數(shù)據(jù)均勻分布在 0 到 255 之間。當(dāng)數(shù)據(jù)排序時(shí),大約前一半的迭代不會(huì)進(jìn)入 if 語(yǔ)句。之后,都會(huì)進(jìn)入if語(yǔ)句。

這對(duì)于分支預(yù)測(cè)器非常友好,因?yàn)榉种нB續(xù)多次走向同一方向。即使是簡(jiǎn)單的飽和計(jì)數(shù)器也能正確預(yù)測(cè)分支,除了切換方向后的幾次迭代之外。

快速可視化:

T = branch taken
N = branch not taken

data[] = 0, 1, 2, 3, 4, ... 126, 127, 128, 129, 130, ... 250, 251, 252, ...
branch = N  N  N  N  N  ...   N    N    T    T    T  ...   T    T    T  ...

       = NNNNNNNNNNNN ... NNNNNNNTTTTTTTTT ... TTTTTTTTTT  (easy to predict)

然而,當(dāng)數(shù)據(jù)完全隨機(jī)時(shí),分支預(yù)測(cè)器就變得毫無(wú)用處,因?yàn)樗鼰o(wú)法預(yù)測(cè)隨機(jī)數(shù)據(jù)。因此,可能會(huì)有大約 50% 的錯(cuò)誤預(yù)測(cè)(并不比隨機(jī)猜測(cè)更好)。

data[] = 226, 185, 125, 158, 198, 144, 217, 79, 202, 118,  14, 150, 177, 182, ...
branch =   T,   T,   N,   T,   T,   T,   T,  N,   T,   N,   N,   T,   T,   T  ...

       = TTNTTTTNTNNTTT ...   (completely random - impossible to predict)

可以做什么?

如果編譯器無(wú)法將分支優(yōu)化為條件移動(dòng),并且愿意犧牲可讀性來(lái)提高性能,則可以嘗試一些技巧。

代替:

if (data[c] >= 128)
    sum += data[c];

和:

int t = (data[c] - 128) >> 31;sum += ~t & data[c];

這消除了分支并用一些按位運(yùn)算代替它。

(請(qǐng)注意,此 hack 并不嚴(yán)格等同于原始 if 語(yǔ)句。但在這種情況下,它對(duì) 的所有輸入值都有效data[]。)

基準(zhǔn)測(cè)試:酷睿 i7 920 @ 3.5 GHz

C++ - Visual Studio 2010 - x64 版本

設(shè)想時(shí)間(秒)
分支 - 隨機(jī)數(shù)據(jù)11.777
分支 - 排序數(shù)據(jù)2.352
無(wú)分支 - 隨機(jī)數(shù)據(jù)2.564
Branchless - 排序數(shù)據(jù)2.587

Java - NetBeans 7.1.1 JDK 7 - x64

設(shè)想時(shí)間(秒)
分支 - 隨機(jī)數(shù)據(jù)10.93293813
分支 - 排序數(shù)據(jù)5.643797077
無(wú)分支 - 隨機(jī)數(shù)據(jù)3.113581453
Branchless - 排序數(shù)據(jù)3.186068823

觀察結(jié)果:

  • 使用分支:排序數(shù)據(jù)和未排序數(shù)據(jù)之間存在巨大差異。

  • 使用 Hack:排序數(shù)據(jù)和未排序數(shù)據(jù)之間沒(méi)有區(qū)別。

  • 在 C++ 情況下,當(dāng)數(shù)據(jù)排序時(shí), hack 實(shí)際上比分支慢一點(diǎn)。

一般的經(jīng)驗(yàn)法則是避免關(guān)鍵循環(huán)中的數(shù)據(jù)相關(guān)分支(例如本例中)。


更新:

  • -O3x64上的 GCC 4.6.1-ftree-vectorize能夠生成條件移動(dòng),因此排序數(shù)據(jù)和未排序數(shù)據(jù)之間沒(méi)有區(qū)別 - 兩者都很快。

    (或者有點(diǎn)快:對(duì)于已經(jīng)排序的情況,cmov可能會(huì)更慢,特別是如果 GCC 將其放在關(guān)鍵路徑上而不只是add,特別是在 Broadwell 之前的 Intel 上,其中cmov有 2 個(gè)周期延遲:gcc 優(yōu)化標(biāo)志 -O3 使代碼比 -O2 慢)

  • 即使在/Ox.

  • 英特爾 C++ 編譯器(ICC) 11 創(chuàng)造了奇跡。它交換兩個(gè)循環(huán),從而將不可預(yù)測(cè)的分支提升到外循環(huán)。它不僅不受錯(cuò)誤預(yù)測(cè)的影響,而且速度是 VC++ 和 GCC 生成速度的兩倍!換句話說(shuō),ICC 利用測(cè)試循環(huán)擊敗了基準(zhǔn)測(cè)試......

  • 如果您為英特爾編譯器提供無(wú)分支代碼,它會(huì)直接對(duì)其進(jìn)行矢量化......并且與分支(使用循環(huán)交換)一樣快。

這表明即使是成熟的現(xiàn)代編譯器優(yōu)化代碼的能力也可能有很大差異......



到此這篇關(guān)于為什么處理已排序的數(shù)組比處理未排序的數(shù)組更快?的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

原文地址:http://www.zghlxwxcb.cn/article/276.html

如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)聯(lián)系站長(zhǎng)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 一個(gè)操作讓數(shù)組處理速度快了5倍,到底是為什么

    一個(gè)操作讓數(shù)組處理速度快了5倍,到底是為什么

    ? 概述: 通過(guò)對(duì)數(shù)組進(jìn)行排序,代碼更好地利用了緩存,從而提高了程序的性能。這種現(xiàn)象通常被稱(chēng)為\\\"緩存友好\\\"(cache-friendly)或\\\"空間局部性\\\"(spatial locality) 今天做一個(gè)數(shù)組數(shù)據(jù)計(jì)算時(shí),發(fā)現(xiàn)一個(gè)效率問(wèn)題,給大家分享一下 一個(gè)數(shù)組排序和不排序時(shí)同樣的邏輯處理速度是

    2024年03月24日
    瀏覽(24)
  • 【排序算法】插入排序與希爾排序,你不想知道為什么希爾比插入更快嗎?

    【排序算法】插入排序與希爾排序,你不想知道為什么希爾比插入更快嗎?

    大家好?。”疚陌⑤x講介紹插入排序和希爾排序,并將解釋為什么希爾排序比插入排序更快。 插入排序,實(shí)際上是我們平時(shí)都使用過(guò)的排序,為什么這么說(shuō)呢???想必大家都玩過(guò)撲克牌吧,大家是如何整理手中的牌的呢?一定是想下面這樣對(duì)吧?? 沒(méi)錯(cuò),插入排序也是的么實(shí)

    2024年02月02日
    瀏覽(25)
  • Redis的速度不夠用?為什么你應(yīng)該考慮使用 KeyDB,一個(gè)更快、更強(qiáng)大、更靈活的開(kāi)源數(shù)據(jù)庫(kù)

    Redis的速度不夠用?為什么你應(yīng)該考慮使用 KeyDB,一個(gè)更快、更強(qiáng)大、更靈活的開(kāi)源數(shù)據(jù)庫(kù)

    你是否正在使用?Redis?作為您的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ),享受它的高性能、高可用的特性?如果是這樣,那么你可能會(huì)對(duì)?KeyDB?感興趣。 KeyDB?一個(gè)由?Snap?提供支持、專(zhuān)為擴(kuò)展而構(gòu)建的開(kāi)源數(shù)據(jù)庫(kù)。它是?Redis?的高性能分支,專(zhuān)注于多線程、內(nèi)存效率和高吞吐量。KeyDB?采用?MVCC?體系

    2024年02月08日
    瀏覽(31)
  • 為什么 Python 代碼在函數(shù)中運(yùn)行得更快?

    哈嘍大家好,我是咸魚(yú) 當(dāng)談到編程效率和性能優(yōu)化時(shí),Python 常常被調(diào)侃為“慢如蝸?!?有趣的是,Python 代碼在函數(shù)中運(yùn)行往往比在全局范圍內(nèi)運(yùn)行要快得多 小伙伴們可能會(huì)有這個(gè)疑問(wèn):為什么在函數(shù)中運(yùn)行的 Python 代碼速度更快? 今天這篇文章將會(huì)解答大家心中的疑惑 原

    2024年02月08日
    瀏覽(21)
  • 為什么list.sort()比Stream().sorted()更快?

    為什么list.sort()比Stream().sorted()更快?

    真的更好嗎? 先簡(jiǎn)單寫(xiě)個(gè)demo 輸出 由此可見(jiàn)list原生排序性能更好。 能證明嗎? 證據(jù)錯(cuò)了。 再把demo變換一下,先輸出stream.sort 此時(shí)輸出變成了 這能證明上面的結(jié)論錯(cuò)誤了嗎? 都不能。 兩種方式都不能證明什么。 使用這種方式在很多場(chǎng)景下是不夠的,某些場(chǎng)景下,JVM會(huì)對(duì)代

    2024年02月14日
    瀏覽(20)
  • 為什么 list.sort() 比 stream().sorted() 要更快?測(cè)試結(jié)果把我驚呆了!

    為什么 list.sort() 比 stream().sorted() 要更快?測(cè)試結(jié)果把我驚呆了!

    作者:是奉壹呀 來(lái)源:juejin.cn/post/7262274383287500860 看到一個(gè)評(píng)論,里面提到了list.sort()和list.strem().sorted()排序的差異。 說(shuō)到list sort()排序比stream().sorted()排序性能更好,但沒(méi)說(shuō)到為什么。 有朋友也提到了這一點(diǎn)。本文重新開(kāi)始,先問(wèn)是不是,再問(wèn)為什么。 推薦一個(gè)開(kāi)源免費(fèi)的

    2024年02月09日
    瀏覽(19)
  • ElasticSearch(七):ES查詢速度為什么那么快

    ElasticSearch(七):ES查詢速度為什么那么快

    介紹給大家一個(gè)開(kāi)源SpringCloud項(xiàng)目。整合了大部分開(kāi)源中間件,詳情信息可以查看文檔: spring cloud開(kāi)源組件開(kāi)發(fā) 另外自己以后博客所講解的代碼內(nèi)容,都會(huì)我的Git上同步(GitHub同步)GIT地址 ES使用的數(shù)據(jù)結(jié)構(gòu)是倒排索引,在對(duì)搜索內(nèi)容進(jìn)行分詞的時(shí)候,會(huì)根據(jù)搜索內(nèi)容分詞結(jié)

    2023年04月08日
    瀏覽(31)
  • Windows 程序開(kāi)機(jī)自啟動(dòng)速度優(yōu)化,為什么騰訊會(huì)議自啟動(dòng)速度那么高?

    Windows 程序開(kāi)機(jī)自啟動(dòng)速度優(yōu)化,為什么騰訊會(huì)議自啟動(dòng)速度那么高?

    目錄 一、問(wèn)題的說(shuō)明和定義 二、問(wèn)題的分析 1.問(wèn)題初步分析 2.詳細(xì)的分析: 2.1Windows常見(jiàn)的自啟動(dòng)方式 2.2Windows常見(jiàn)的自啟動(dòng)方式的細(xì)節(jié)分析 三、問(wèn)題的解決方案 1、為什么騰訊會(huì)議Rooms那么快 2.我們是否可以跟騰訊會(huì)議一樣快 這兩天有個(gè)優(yōu)化項(xiàng)需要做個(gè)技術(shù)調(diào)研,就是我們

    2024年02月02日
    瀏覽(25)
  • ElasticSearch第七講:ES查詢速度為什么那么快

    ElasticSearch第七講:ES查詢速度為什么那么快

    介紹給大家一個(gè)開(kāi)源SpringCloud項(xiàng)目。整合了大部分開(kāi)源中間件,詳情信息可以查看文檔: spring cloud開(kāi)源組件開(kāi)發(fā) 另外自己以后博客所講解的代碼內(nèi)容,都會(huì)我的Git上同步(GitHub同步)GIT地址 ES使用的數(shù)據(jù)結(jié)構(gòu)是倒排索引,在對(duì)搜索內(nèi)容進(jìn)行分詞的時(shí)候,會(huì)根據(jù)搜索內(nèi)容分詞結(jié)

    2023年04月19日
    瀏覽(23)
  • ElasticSearch第七講 ES查詢速度為什么那么快

    ElasticSearch第七講 ES查詢速度為什么那么快

    介紹給大家一個(gè)開(kāi)源SpringCloud項(xiàng)目。整合了大部分開(kāi)源中間件,詳情信息可以查看文檔: spring cloud開(kāi)源組件開(kāi)發(fā) 另外自己以后博客所講解的代碼內(nèi)容,都會(huì)我的Git上同步(GitHub同步)GIT地址 ES使用的數(shù)據(jù)結(jié)構(gòu)是倒排索引,在對(duì)搜索內(nèi)容進(jìn)行分詞的時(shí)候,會(huì)根據(jù)搜索內(nèi)容分詞結(jié)

    2023年04月25日
    瀏覽(31)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包