Lange Version...
Ein Mitarbeiter behauptete heute, nachdem er meine Verwendung while (1)
in einem Perl-Skript gesehen hatte, for (;;)
das schneller ist. Ich argumentierte, dass sie gleich sein sollten, in der Hoffnung, dass der Dolmetscher alle Unterschiede optimieren würde. Ich habe ein Skript eingerichtet, das 1.000.000.000 für Schleifeniterationen und die gleiche Anzahl von while-Schleifen ausführt und die Zeit dazwischen aufzeichnet. Ich konnte keinen nennenswerten Unterschied feststellen. Mein Kollege sagte, ein Professor habe ihm gesagt, dass der while (1)
einen Vergleich mache 1 == 1
und der for (;;)
nicht. Wir haben den gleichen Test mit dem 100-fachen der Anzahl der Iterationen mit C ++ wiederholt und der Unterschied war vernachlässigbar. Es war jedoch ein anschauliches Beispiel dafür, wie viel schneller kompilierter Code im Vergleich zu einer Skriptsprache sein kann.
Kurzfassung ...
Gibt es einen Grund, eine while (1)
gegenüber einer zu bevorzugen, for (;;)
wenn Sie eine Endlosschleife benötigen, aus der Sie ausbrechen können?
Hinweis: Wenn es aus der Frage nicht klar ist. Dies war eine rein lustige akademische Diskussion zwischen ein paar Freunden. Mir ist bewusst, dass dies kein überaus wichtiges Konzept ist, über das sich alle Programmierer quälen sollten. Vielen Dank für all die tollen Antworten, die ich (und ich bin sicher andere) aus dieser Diskussion gelernt habe.
Update: Der oben genannte Mitarbeiter hat mit einer Antwort unten gewogen.
Zitiert hier für den Fall, dass es begraben wird.
Es kam von einem AMD-Montageprogrammierer. Er erklärte, dass C-Programmierer (die Leute) nicht erkennen, dass ihr Code Ineffizienzen aufweist. Er sagte heute jedoch, dass gcc-Compiler sehr gut sind und Leute wie ihn aus dem Geschäft bringen. Er sagte zum Beispiel, und erzählte mir von dem
while 1
vsfor(;;)
. Ich benutze es jetzt aus Gewohnheit, aber gcc und insbesondere Dolmetscher werden heutzutage für beide die gleiche Operation (einen Prozessorsprung) ausführen, da sie optimiert sind.
quelle
Antworten:
In Perl führen sie zu denselben Opcodes:
Ebenso in GCC:
Ich denke, die Antwort ist, dass sie in vielen Compilern gleich sind. Natürlich muss dies für einige andere Compiler nicht unbedingt der Fall sein, aber es besteht die Möglichkeit, dass der Code innerhalb der Schleife ein paar tausend Mal teurer ist als die Schleife selbst. Wen interessiert das?
quelle
Mit GCC scheinen beide in derselben Assemblersprache zu kompilieren:
quelle
Es gibt nicht viel Grund, einen dem anderen vorzuziehen. Ich denke das
while(1)
und ist vor allemwhile(true)
besser lesbar alsfor(;;)
, aber das ist nur meine Präferenz.quelle
forever
es sich um ein eigenes Token handelt.Es gibt keinen Unterschied nach dem Standard. 6.5.3 / 1 hat:
Und 6.5.3 / 2 hat:
Also nach dem C ++ Standard der Code:
ist genau das gleiche wie:
quelle
Der Visual C ++ - Compiler, mit dem eine Warnung für ausgegeben wird
(konstanter Ausdruck) aber nicht für
Ich habe
for (;;)
aus diesem Grund die Praxis des Bevorzugens fortgesetzt , aber ich weiß nicht, ob der Compiler dies heutzutage noch tut.quelle
for(;;)
ist ein Zeichen weniger, das Sie eingeben müssen, wenn Sie in diese Richtung gehen möchten, um die Dinge zu optimieren.quelle
Turbo C mit diesen alten Compilern
for(;;)
führt dann zu schnellerem Codewhile(1)
.Heutzutage optimieren gcc, Visual C (ich denke fast alle) Compiler gut, und CPUs mit 4,7 MHz werden selten verwendet.
In jenen Tagen
for( i=10; i; i-- )
war a schneller alsfor( i=1; i <=10; i++ )
, da der Vergleichi
0 ist, was zu einem bedingten CPU-Zero-Flag-Sprung führt. Und das Zero-Flag wurde mit der letzten Dekrementierungsoperation geändert( i-- )
, es ist keine zusätzliche cmp-Operation erforderlich.und hier mit
for(i=1; i<=10; i++)
mit extra cmpl:quelle
Für alle Leute, die argumentieren, Sie sollten keine unbestimmten while-Schleifen verwenden und dumme Sachen vorschlagen, wie die Verwendung von offenen Goto (ernsthaft, autsch)
Kann auf andere Weise nicht wirklich effektiv dargestellt werden. Nicht ohne eine Exit-Variable zu erstellen und schwarze Magie zu betreiben, um sie synchron zu halten.
Wenn Sie eine Vorliebe für die goto-artigere Syntax haben, verwenden Sie etwas Vernünftiges, das den Umfang einschränkt.
Letztendlich ist Geschwindigkeit nicht so wichtig
Es ist eine enorme Zeitverschwendung, sich Gedanken darüber zu machen, wie effektiv die Geschwindigkeit verschiedener Schleifenkonstrukte ist. Vorzeitige Optimierung durch und durch. Ich kann mir keine Situation vorstellen, in der Profiling-Code Engpässe bei der Auswahl des Schleifenkonstrukts festgestellt hat.
Im Allgemeinen ist es das Wie der Schleife und das Was der Schleife.
Sie sollten die Lesbarkeit und Prägnanz "optimieren" und alles schreiben, was am besten geeignet ist, um das Problem dem nächsten armen Trottel zu erklären, der Ihren Code findet.
Wenn Sie den Trick "goto LABEL" verwenden, den jemand erwähnt hat, und ich Ihren Code verwenden muss, sollten Sie darauf vorbereitet sein, mit einem offenen Auge zu schlafen, insbesondere wenn Sie dies mehr als einmal tun, da solche Dinge schrecklich Spaghetti-Code erzeugen.
Nur weil Sie Spaghetti-Code erstellen können , heißt das nicht, dass Sie es sollten
quelle
Aus Stroustrup, TC ++ PL (3. Auflage), §6.1.1:
Ich bevorzuge
for (;;)
.quelle
Wenn der Compiler keine Optimierung durchführt,
for(;;)
wäre er immer schneller alswhile(true)
. Dies liegt daran, dass while-Anweisung die Bedingung jedes Mal auswertet, for-Anweisung jedoch ein bedingungsloser Sprung ist. Wenn der Compiler den Kontrollfluss optimiert, werden möglicherweise einige Opcodes generiert. Sie können den Demontagecode sehr einfach lesen.PS Sie könnten eine Endlosschleife wie folgt schreiben:
quelle
Ich habe einmal davon gehört.
Es kam von einem AMD-Montageprogrammierer. Er erklärte, dass C-Programmierer (die Leute) nicht erkennen, dass ihr Code Ineffizienzen aufweist. Er sagte heute jedoch, dass gcc-Compiler sehr gut sind und Leute wie ihn aus dem Geschäft bringen. Er sagte zum Beispiel, und erzählte mir von dem
while 1
vsfor(;;)
. Ich benutze es jetzt aus Gewohnheit, aber gcc und insbesondere Dolmetscher werden heutzutage für beide die gleiche Operation (einen Prozessorsprung) ausführen, da sie optimiert sind.quelle
In einem optimierten Build einer kompilierten Sprache sollte es keinen nennenswerten Unterschied zwischen den beiden geben. Keiner sollte zur Laufzeit Vergleiche durchführen, er führt nur den Schleifencode aus, bis Sie die Schleife manuell verlassen (z
break
. B. mit a ).quelle
Ich bin überrascht, dass niemand richtig
for (;;)
gegenwhile (1)
Perl getestet hat !Da Perl eine interpretierte Sprache ist, besteht die Zeit zum Ausführen eines Perl-Skripts nicht nur aus der Ausführungsphase (die in diesem Fall dieselbe ist), sondern auch aus der Interpretationsphase vor der Ausführung. Beide Phasen müssen bei einem Geschwindigkeitsvergleich berücksichtigt werden.
Glücklicherweise hat Perl ein praktisches Benchmark-Modul, mit dem wir einen Benchmark wie folgt implementieren können:
Beachten Sie, dass ich zwei verschiedene Versionen der Endlosschleife für for teste: eine, die kürzer als die while-Schleife ist, und eine andere, die zusätzlichen Platz hat, damit sie dieselbe Länge wie die while-Schleife hat.
Unter Ubuntu 11.04 x86_64 mit Perl 5.10.1 erhalte ich folgende Ergebnisse:
Die while-Schleife ist eindeutig der Gewinner auf dieser Plattform.
Unter FreeBSD 8.2 x86_64 mit Perl 5.14.1:
While-Schleife ist auch hier der Gewinner.
Auf FreeBSD 8.2 i386 mit Perl 5.14.1:
Überraschenderweise ist die for-Schleife mit zusätzlichem Leerzeichen hier die schnellste Wahl!
Mein Fazit ist, dass die while-Schleife auf der x86_64-Plattform verwendet werden sollte, wenn der Programmierer die Geschwindigkeit optimiert. Offensichtlich sollte bei der Raumoptimierung eine for-Schleife verwendet werden. Meine Ergebnisse sind in Bezug auf andere Plattformen leider nicht schlüssig.
quelle
Benchmark
hat seine Grenzen und kann nicht verwendet werden, um schnell von langsam zu unterscheiden, wenn die Ergebnisse innerhalb von 7% voneinander liegen. Darüber hinaus haben Sie den Unterschied zwischen derfor
und derwhile
Schleife nicht getestet, da jedes Subdie
vor Erreichen der Schleifen selbst wird. Und seit wann war die Menge an Leerzeichen für den Perl-Interpreter von Bedeutung? Sorry, aber die Analyse ist extrem fehlerhaft.die
steht in meinem Code, weil ich nur den Unterschied in der Kompilierungszeit testen möchte . Wie andere bereits darauf hingewiesen haben, ist der resultierende Bytecode identisch, daher macht es keinen Sinn, dies zu testen. Überraschenderweise scheint die Menge an Leerraum in meinen Testumgebungen in diesem Fall einen kleinen Unterschied zu machen. Es könnte etwas damit zu tun haben, wie die Charaktere im Speicher ausgerichtet werden oder ähnliches ...Benchmark
nicht eindeutig. Vertraue diesem Unterschied von 1% überhaupt nicht!-60
führt den Test 60 Sekunden lang aus.Theoretisch könnte ein völlig naiver Compiler das Literal '1' in der Binärdatei speichern (Speicherplatz verschwenden) und prüfen, ob bei jeder Iteration 1 == 0 ist (Zeitverschwendung und mehr Speicherplatz).
In der Realität werden Compiler jedoch auch ohne "keine" Optimierungen beide auf das Gleiche reduzieren. Sie können auch Warnungen ausgeben, da dies auf einen logischen Fehler hinweisen kann. Zum Beispiel könnte das Argument von
while
woanders definiert werden und Sie erkennen nicht, dass es konstant ist.quelle
Ich bin überrascht, dass niemand die direktere Form angeboten hat, die der gewünschten Baugruppe entspricht:
quelle
{ forever: do stuff; goto forever; }
)while(1)
ist eine Redewendung,for(;;)
die von den meisten Compilern erkannt wird.Ich war froh zu sehen, dass Perl auch erkennt
until(0)
.quelle
Um die
for (;;)
vs-while (1)
Debatte zusammenzufassen: Es ist offensichtlich, dass erstere in den Tagen älterer, nicht optimierender Compiler schneller war. Aus diesem Grund wird sie in älteren Codebasen wie Lions Unix-Quellcodekommentaren verwendet, jedoch im Zeitalter der Badass-Optimierung Compiler diese Gewinne sind weggekoppelt, da ich der Meinung bin, dass letzteres leichter zu verstehen ist als erstere.quelle
Bin gerade auf diesen Thread gestoßen (obwohl einige Jahre zu spät).
Ich glaube, ich habe den eigentlichen Grund gefunden, warum "for (;;)" besser ist als "while (1)".
gemäß dem "Barr Coding Standard 2018"
Im Grunde ist dies kein Geschwindigkeitsproblem, sondern ein Problem der Lesbarkeit. Abhängig von der Schriftart / dem Druck des Codes kann die Nummer eins (1) in einer Weile wie ein Kleinbuchstabe l aussehen.
dh 1 vs l. (In einigen Schriftarten sehen diese identisch aus).
Während (1) wie eine while-Schleife aussehen kann, die vom variablen Buchstaben L abhängt.
while (true) funktioniert möglicherweise auch, aber in einigen älteren C- und eingebetteten C-Fällen sind true / false noch nicht definiert, es sei denn, stdbool.h ist enthalten.
quelle
l
, nicht diese,1
undl
ähnlich aussehen können.Ich würde denken, dass beide in Bezug auf die Leistung gleich sind. Ich würde zwar while (1) für die Lesbarkeit bevorzugen, aber ich frage mich, warum Sie eine Endlosschleife benötigen.
quelle
Sie sind gleich. Es gibt viel wichtigere Fragen zum Nachdenken.
Mein Punkt, der oben impliziert, aber nicht explizit gemacht wurde, ist, dass ein anständiger Compiler für beide Schleifenformen genau den gleichen Code generieren würde. Der größere Punkt ist, dass das Schleifenkonstrukt einen kleinen Teil der Laufzeit eines Algorithmus ausmacht und Sie zunächst sicherstellen müssen, dass Sie den Algorithmus und alles andere, was damit zusammenhängt, optimiert haben. Die Optimierung Ihres Schleifenkonstrukts sollte unbedingt ganz unten auf Ihrer Prioritätenliste stehen.
quelle