Ist “==” in einem sortierten Array nicht schneller als ein unsortiertes Array? [duplicate]

Lesezeit: 6 Minuten

Benutzeravatar von ggrr
ggrr

Hinweis: Die angebliche doppelte Frage bezieht sich meiner Meinung nach hauptsächlich auf den Vergleich von “<" und ">“, aber nicht auf den Vergleich von “==” und beantwortet daher nicht meine Frage zur Leistung des Operators “==”.

Ich habe lange geglaubt, dass die “Verarbeitung” eines sortierten Arrays schneller sein sollte als ein unsortiertes Array. Zuerst dachte ich, dass die Verwendung von “==” in einem sortierten Array schneller sein sollte als in einem unsortierten Array, weil – denke ich – die Verzweigungsvorhersage funktioniert:

UNSORTIERTES ARRAY:

5 == 100 F
43 == 100 F
100 == 100 T
250 == 100 F
6 == 100 F
(other elements to check)

SORTIERTE ARRAY:

5 == 100 F
6 == 100 F
43 == 100 F
100 == 100 T
(no need to check other elements, so all are F)

also denke ich, dass SORTEDARRAY schneller sein sollte als UNSORTEDARRAY, aber heute habe ich den Code verwendet, um 2 Arrays in einem Header zum Testen zu generieren, und die Verzweigungsvorhersage schien nicht so zu funktionieren, wie ich dachte.

Ich habe ein unsortiertes Array und ein sortiertes Array zum Testen generiert:

srand(time(NULL));
int UNSORTEDARRAY[524288];
int SORTEDARRAY[sizeof(UNSORTEDARRAY)/sizeof(int)];
for(int i=0;i<sizeof(SORTEDARRAY)/sizeof(int);i++){
    SORTEDARRAY[i]=UNSORTEDARRAY[i]=rand();
}
sort(SORTEDARRAY,SORTEDARRAY+sizeof(SORTEDARRAY)/sizeof(int));
string u="const int UNSORTEDARRAY[]={";
string s="const int SORTEDARRAY[]={";
for(int i=0;i<sizeof(UNSORTEDARRAY)/sizeof(int);i++){
    u+=to_string(UNSORTEDARRAY[i])+",";
    s+=to_string(SORTEDARRAY[i])+",";
}
u.erase(u.end()-1);
s.erase(s.end()-1);
u+="};\n";
s+="};\n";
ofstream out("number.h");
string code=u+s;
out << code;
out.close();

zählen Sie also zum Testen einfach, ob der Wert == RAND_MAX/2 ist:

#include "number.h"
int main(){
int count;
    clock_t start = clock();
    for(int i=0;i<sizeof(SORTEDARRAY)/sizeof(int);i++){
        if(SORTEDARRAY[i]==RAND_MAX/2){
            count++;
        }
    }
    printf("%f\n",(float)(clock()-start)/CLOCKS_PER_SEC);
}

3x laufen:

UNSORTIERTE REIHE

0.005376
0.005239
0.005220

SORTIERTE ARRAY

0.005334
0.005120
0.005223

Es scheint ein kleiner Leistungsunterschied zu sein, also habe ich es nicht geglaubt und dann versucht, “SORTEDARRAY[i]==RAND_MAX/2” bis “SORTEDARRAY[i]>RAND_MAX/2”, um zu sehen, ob es einen Unterschied gemacht hat:

UNSORTIERTE REIHE

0.008407
0.008363
0.008606

SORTIERTE ARRAY

0.005306
0.005227
0.005146

Diesmal gibt es einen großen Unterschied.

Ist “==” im sortierten Array nicht schneller als ein unsortiertes Array? Wenn ja, warum ist “>” in einem sortierten Array schneller als ein unsortiertes Array, aber “==” nicht?

  • Bezogen auf eine der am meisten positiv bewerteten Fragen aller Zeiten: stackoverflow.com/questions/11227809/…

    – Andrzej Pronobis

    18. August 2015 um 3:59 Uhr


  • “Ich glaube, die “Verarbeitung” eines sortierten Arrays sollte schneller sein als ein unsortiertes Array”: Versuchen Sie sich selbst zu beantworten, warum Sie glauben, dass dies für diesen Algorithmus gilt. Das heißt, welche Art von Arbeit und wie viel davon Sie für jeden Fall tun. Sie können erkennen, was die Antwort ist.

    – Viraptor

    18. August 2015 um 4:02 Uhr

  • string ist kein Standardtyp in C, und die Verwendung von += Operator mit einem Operanden vom Typ string und der andere char * macht keinen Sinn. Sind Sie sicher, dass dies kein C++-Code ist?

    – autistisch

    18. August 2015 um 5:29 Uhr

  • Was verwenden Sie außerdem, um diesen Code zu timen? Etwas sehr ungenau und wahrscheinlich voreingenommen. Diese Art von Frage wird normalerweise von falsch informierten Personen geschrieben. Haben Sie überhaupt die vollständige Optimierung aktiviert? Haben Sie ein wirklich realistisches Problem zu lösen und ein Programm, um dieses Problem zu lösen? Verwenden Sie einen Profiler für dieses Programm, um festzustellen, was die wesentlichen Engpässe sind? Der Grund, warum ich frage, ist, dass die Engpässe in jedem realistischen Szenario erheblich von dem abweichen werden, was Sie beschrieben haben. Diese Frage hat keinen praktischen Nutzen.

    – autistisch

    18. August 2015 um 5:35 Uhr


  • Warum nehmen Sie an “(keine Notwendigkeit, andere Elemente zu überprüfen, also sind alle F)”? Der Compiler kann das nicht wissen, er wird einfach blind jeden Speicherplatz inspizieren. Tatsächlich wird er bei Verwendung von Zufallsdaten nur selten gleich einem festen Wert sein, wodurch er von der CPU sehr leicht vorhergesagt werden kann.

    – Mihai Timar

    23. Februar 2017 um 12:42 Uhr

Eine Sache, die einem sofort in den Sinn kommt, ist der Verzweigungsvorhersagealgorithmus der CPU.

Im Falle von > Im Vergleich dazu ist das Verzweigungsverhalten in sortierten Arrays sehr konsistent: Erstens, die if Bedingung konsequent falsch ist, dann ist sie konsequent wahr. Dies passt selbst zur einfachsten Verzweigungsvorhersage sehr gut.

In unsortiertem Array das Ergebnis von > Die Bedingung ist im Wesentlichen zufällig, wodurch jede Verzweigungsvorhersage vereitelt wird.

Dadurch wird die sortierte Version schneller.

Im Falle von == Im Vergleich dazu ist die Bedingung meistens falsch und nur sehr selten wahr. Dies funktioniert gut mit der Verzweigungsvorhersage, unabhängig davon, ob das Array sortiert ist oder nicht. Die Zeiten sind im Wesentlichen gleich.

Benutzeravatar von imallett
imallett

NB Ich mache dies zu einer Antwort, da es für einen Kommentar zu lang ist.

Die Wirkung hier ist genau das, was in den zahlreichen Antworten auf diese Frage bereits sehr ausführlich erläutert wurde. Die Verarbeitung eines sortierten Arrays war in diesem Fall aufgrund der Verzweigungsvorhersage schneller.

Auch hier ist die Verzweigungsvorhersage der Übeltäter. Das == Der Test ist sehr selten wahr, daher funktioniert die Verzweigungsvorhersage für beide ungefähr gleich. Als Sie es geändert haben >dann haben Sie das in dieser Frage erklärte Verhalten und aus demselben Grund.


Moral:

Ich glaube, dass die “Verarbeitung” eines sortierten Arrays schneller sein sollte als [an ]unsortiertes Array.

Du musst wissen warum. Das ist keine magische Regel, und es ist nicht immer wahr.

Der Vergleich == hat weniger mit dem Bestellen zu tun als > tut. Richtig oder falsch vorhersagen == nur von der Anzahl der doppelten Werte und deren Verteilung abhängen würde.

Sie können verwenden perf stat um die Leistungszähler anzuzeigen…

jason@io /tmp $ lz4 -d ints | perf stat ./proc-eq >/dev/null
Successfully decoded 104824717 bytes

 Performance counter stats for './proc-eq':

       5226.932577      task-clock (msec)         #    0.953 CPUs utilized
                31      context-switches          #    0.006 K/sec
                24      cpu-migrations            #    0.005 K/sec
             3,479      page-faults               #    0.666 K/sec
    15,763,486,767      cycles                    #    3.016 GHz
     4,238,973,549      stalled-cycles-frontend   #   26.89% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,522,072,416      instructions              #    2.00  insns per cycle
                                                  #    0.13  stalled cycles per insn
     8,515,545,178      branches                  # 1629.167 M/sec
        10,261,743      branch-misses             #    0.12% of all branches

       5.483071045 seconds time elapsed

jason@io /tmp $ lz4 -d ints | sort -n | perf stat ./proc-eq >/dev/null
Successfully decoded 104824717 bytes

 Performance counter stats for './proc-eq':

       5536.031410      task-clock (msec)         #    0.348 CPUs utilized
               198      context-switches          #    0.036 K/sec
                21      cpu-migrations            #    0.004 K/sec
             3,604      page-faults               #    0.651 K/sec
    16,870,541,124      cycles                    #    3.047 GHz
     5,300,218,855      stalled-cycles-frontend   #   31.42% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,526,006,118      instructions              #    1.87  insns per cycle
                                                  #    0.17  stalled cycles per insn
     8,516,336,829      branches                  # 1538.347 M/sec
        10,980,571      branch-misses             #    0.13% of all branches

jason@io /tmp $ lz4 -d ints | perf stat ./proc-gt >/dev/null
Successfully decoded 104824717 bytes

 Performance counter stats for './proc-gt':

       5293.065703      task-clock (msec)         #    0.957 CPUs utilized
                38      context-switches          #    0.007 K/sec
                50      cpu-migrations            #    0.009 K/sec
             3,466      page-faults               #    0.655 K/sec
    15,972,451,322      cycles                    #    3.018 GHz
     4,350,726,606      stalled-cycles-frontend   #   27.24% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,537,365,299      instructions              #    1.97  insns per cycle
                                                  #    0.14  stalled cycles per insn
     8,515,606,640      branches                  # 1608.823 M/sec
        15,241,198      branch-misses             #    0.18% of all branches

       5.532285374 seconds time elapsed

jason@io /tmp $ lz4 -d ints | sort -n | perf stat ./proc-gt >/dev/null

      15.930144154 seconds time elapsed

 Performance counter stats for './proc-gt':

       5203.873321      task-clock (msec)         #    0.339 CPUs utilized
                 7      context-switches          #    0.001 K/sec
                22      cpu-migrations            #    0.004 K/sec
             3,459      page-faults               #    0.665 K/sec
    15,830,273,846      cycles                    #    3.042 GHz
     4,456,369,958      stalled-cycles-frontend   #   28.15% frontend cycles idle
   <not supported>      stalled-cycles-backend
    31,540,409,224      instructions              #    1.99  insns per cycle
                                                  #    0.14  stalled cycles per insn
     8,516,186,042      branches                  # 1636.509 M/sec
        10,205,058      branch-misses             #    0.12% of all branches

      15.365528326 seconds time elapsed

1413160cookie-checkIst “==” in einem sortierten Array nicht schneller als ein unsortiertes Array? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy