web-dev-qa-db-fra.com

Quelle boucle est plus rapide, tant que ou pour?

Vous pouvez obtenir le même résultat avec les boucles for et while:

Tandis que:

$i = 0;
while ($i <= 10){
  print $i."\n";
  $i++;
};

Pour:

for ($i = 0; $i <= 10; $i++){
  print $i."\n";
}

Mais lequel est le plus rapide?

28
Mark Lalor

Cela dépend clairement de l'implémentation particulière de l'interprète/compilateur du langage spécifique.

Cela dit, théoriquement, toute implémentation sensée est susceptible de pouvoir implémenter l’une par rapport à l’autre si elle est plus rapide, la différence doit donc être négligeable. 

Bien sûr, j'ai supposé que while et for se comportaient comme ils le font dans les langages C et similaires. Vous pouvez créer une langue avec une sémantique complètement différente pour while et for

21
Mehrdad Afshari

En C #, la boucle For est légèrement plus rapide. 

Pour la boucle, en moyenne environ 2,95 à 3,02 ms. 

La boucle While était en moyenne d’environ 3,05 à 3,37 ms.

Petite application rapide pour prouver:

 class Program
    {
        static void Main(string[] args)
        {
            int max = 1000000000;
            Stopwatch stopWatch = new Stopwatch();

            if (args.Length == 1 && args[0].ToString() == "While")
            {
                Console.WriteLine("While Loop: ");
                stopWatch.Start();
                WhileLoop(max);
                stopWatch.Stop();
                DisplayElapsedTime(stopWatch.Elapsed);
            }
            else
            {
                Console.WriteLine("For Loop: ");
                stopWatch.Start();
                ForLoop(max);
                stopWatch.Stop();
                DisplayElapsedTime(stopWatch.Elapsed);
            }
        }

        private static void WhileLoop(int max)
        {
            int i = 0;
            while (i <= max)
            {
                //Console.WriteLine(i);
                i++;
            };
        }

        private static void ForLoop(int max)
        {
            for (int i = 0; i <= max; i++)
            {
                //Console.WriteLine(i);
            }
        }

        private static void DisplayElapsedTime(TimeSpan ts)
        {
            // Format and display the TimeSpan value.
            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            Console.WriteLine(elapsedTime, "RunTime");
        }
    }
12
Shane

Je trouve que la boucle la plus rapide est une boucle while while, par exemple:

var i = myArray.length;
while(i--){
  // Do something
}
6
Anthony

Comme d'autres l'ont dit, tout compilateur digne de ce nom générera un code pratiquement identique. Toute différence de performance est négligeable - vous effectuez une micro-optimisation.

La vraie question est: qu'est-ce qui est le plus lisible? Et c'est la boucle for (au moins à mon humble avis).

4
Aillyn

Si c'était un programme C, je ne dirais ni l'un ni l'autre. Le compilateur produira exactement le même code. Comme ce n'est pas le cas, je dis le mesurer. En réalité, il ne s'agit pas de savoir quelle construction de boucle est la plus rapide, car cela représente un gain de temps minime. Il s'agit de savoir quelle construction de boucle est la plus facile à maintenir. Dans le cas que vous avez montré, une boucle for est plus appropriée car c'est ce que les autres programmeurs (y compris l'avenir, espérons-le) s'attendent à voir là.

3
nmichaels

Définissez les itérations de la boucle sur 10 000. 

Trouvez le temps en millisecondes> Exécuter la boucle> trouvez le temps en millisecondes et soustrayez le premier chronomètre.

Faites-le pour les deux codes, quelle que soit la milliseconde la plus basse exécutée plus rapidement. Vous souhaiterez peut-être exécuter le test plusieurs fois et les répartir afin de réduire la probabilité que des processus en arrière-plan influencent le test.

Vous aurez probablement des temps similaires dans les deux cas, mais je voudrais savoir si on est toujours un peu plus rapide.

3
AttackingHobo

J'ai utilisé une boucle for et while sur une machine de test solide (aucun processus d'arrière-plan tiers non standard en cours d'exécution). J'ai exécuté un for loop vs while loop en ce qui concerne la modification de la propriété de style de 10 000 nœuds <button>.

Le test a été exécuté 10 fois consécutives, avec 1 exécution expirée pendant 1 500 millisecondes avant l'exécution:

Voici le javascript très simple que j'ai créé à cet effet

function runPerfTest() {
    "use strict";

    function perfTest(fn, ns) {
        console.time(ns);
        fn();
        console.timeEnd(ns);
    }

    var target = document.getElementsByTagName('button');

    function whileDisplayNone() {
        var x = 0;
        while (target.length > x) {
            target[x].style.display = 'none';
            x++;
        }
    }

    function forLoopDisplayNone() {
        for (var i = 0; i < target.length; i++) {
            target[i].style.display = 'none';
        }
    }

    function reset() {
        for (var i = 0; i < target.length; i++) {
            target[i].style.display = 'inline-block';
        }
    }

    perfTest(function() {
        whileDisplayNone();
    }, 'whileDisplayNone');

    reset();

    perfTest(function() {
        forLoopDisplayNone();
    }, 'forLoopDisplayNone');

    reset();
};

$(function(){
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    setTimeout(function(){
        console.log('cool run');
        runPerfTest();
    }, 1500);
});

Voici les résultats que j'ai obtenus

pen.js:8 whileDisplayNone: 36.987ms
pen.js:8 forLoopDisplayNone: 20.825ms

pen.js:8 whileDisplayNone: 19.072ms
pen.js:8 forLoopDisplayNone: 25.701ms

pen.js:8 whileDisplayNone: 21.534ms
pen.js:8 forLoopDisplayNone: 22.570ms

pen.js:8 whileDisplayNone: 16.339ms
pen.js:8 forLoopDisplayNone: 21.083ms

pen.js:8 whileDisplayNone: 16.971ms
pen.js:8 forLoopDisplayNone: 16.394ms

pen.js:8 whileDisplayNone: 15.734ms
pen.js:8 forLoopDisplayNone: 21.363ms

pen.js:8 whileDisplayNone: 18.682ms
pen.js:8 forLoopDisplayNone: 18.206ms

pen.js:8 whileDisplayNone: 19.371ms
pen.js:8 forLoopDisplayNone: 17.401ms

pen.js:8 whileDisplayNone: 26.123ms
pen.js:8 forLoopDisplayNone: 19.004ms

pen.js:61 cool run
pen.js:8 whileDisplayNone: 20.315ms
pen.js:8 forLoopDisplayNone: 17.462ms

Voici le lien démo

Mettre à jour

Un test séparé que j'ai effectué se trouve ci-dessous et implémente 2 algorithmes factoriels écrits différemment, l'un utilisant une boucle for, l'autre utilisant une boucle while.

Voici le code:

function runPerfTest() {
    "use strict";

    function perfTest(fn, ns) {
        console.time(ns);
        fn();
        console.timeEnd(ns);
    }

    function whileFactorial(num) {
        if (num < 0) {
            return -1;
        }
        else if (num === 0) {
            return 1;
        }
        var factl = num;
        while (num-- > 2) {
            factl *= num;
        }
        return factl;
    }

    function forFactorial(num) {
        var factl = 1;
        for (var cur = 1; cur <= num; cur++) {
            factl *= cur;
        }
        return factl;
    }

    perfTest(function(){
        console.log('Result (100000):'+forFactorial(80));
    }, 'forFactorial100');

    perfTest(function(){
        console.log('Result (100000):'+whileFactorial(80));
    }, 'whileFactorial100');
};

(function(){
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    runPerfTest();
    console.log('cold run @1500ms timeout:');
    setTimeout(runPerfTest, 1500);
})();

Et les résultats pour le repère factoriel:

pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.280ms
pen.js:38 Result (100000):7.156945704626378e+118
pen.js:8 forFactorial100: 0.241ms
pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.254ms
pen.js:38 Result (100000):7.156945704626378e+118
pen.js:8 forFactorial100: 0.254ms
pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.285ms
pen.js:38 Result (100000):7.156945704626378e+118
pen.js:8 forFactorial100: 0.294ms
pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.181ms
pen.js:38 Result (100000):7.156945704626378e+118
pen.js:8 forFactorial100: 0.172ms
pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.195ms
pen.js:38 Result (100000):7.156945704626378e+118
pen.js:8 forFactorial100: 0.279ms
pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.185ms
pen.js:55 cold run @1500ms timeout:
pen.js:38 Result (100000):7.156945704626378e+118
pen.js:8 forFactorial100: 0.404ms
pen.js:41 Result (100000):7.15694570462638e+118
pen.js:8 whileFactorial100: 0.314ms

Conclusion: peu importe la taille de l'échantillon ou le type de tâche spécifique testé, les performances ne sont pas clairement gagnantes entre une boucle while et for. Tests effectués sur un MacAir avec OS X Mavericks sur Chrome evergreen.

1
Alpha G33k

Certains compilateurs optimiseurs seront capables de mieux dérouler la boucle avec une boucle for, mais il est probable que si vous faites quelque chose qui peut être déroulé, un compilateur suffisamment intelligent pour le dérouler est probablement assez intelligent pour interpréter la condition de boucle de votre La boucle While peut aussi se dérouler.

1
Chris

Ils devraient être égaux. La boucle for que vous avez écrite fait exactement la même chose que la boucle while: définir $i=0, imprimer $i et incrémenter $i à la fin de la boucle.

1
murgatroid99

J'ai également essayé de comparer les différents types de boucles en C #. J'ai utilisé le même code que Shane , mais j'ai aussi essayé avec un do-while et je l'ai trouvé le plus rapide. C'est le code:

using System;
using System.Diagnostics;


public class Program
{
    public static void Main()
    {
        int max = 9999999;
        Stopwatch stopWatch = new Stopwatch();

        Console.WriteLine("Do While Loop: ");
        stopWatch.Start();
        DoWhileLoop(max);
        stopWatch.Stop();
        DisplayElapsedTime(stopWatch.Elapsed);
        Console.WriteLine("");
        Console.WriteLine("");

        Console.WriteLine("While Loop: ");
        stopWatch.Start();
        WhileLoop(max);
        stopWatch.Stop();
        DisplayElapsedTime(stopWatch.Elapsed);
        Console.WriteLine("");
        Console.WriteLine("");

        Console.WriteLine("For Loop: ");
        stopWatch.Start();
        ForLoop(max);
        stopWatch.Stop();
        DisplayElapsedTime(stopWatch.Elapsed);
    }

    private static void DoWhileLoop(int max)
    {
        int i = 0;
        do
        {
            //Performe Some Operation. By removing Speed increases
            var j = 10 + 10;
            j += 25;
            i++;
        } while (i <= max);
    }

    private static void WhileLoop(int max)
    {
        int i = 0;
        while (i <= max)
        {
            //Performe Some Operation. By removing Speed increases
            var j = 10 + 10;
            j += 25;
            i++;
        };
    }

    private static void ForLoop(int max)
    {
        for (int i = 0; i <= max; i++)
        {
            //Performe Some Operation. By removing Speed increases
            var j = 10 + 10;
            j += 25;
        }
    }

    private static void DisplayElapsedTime(TimeSpan ts)
    {
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
        Console.WriteLine(elapsedTime, "RunTime");
    }
}

et voici les résultats d'une démo live sur DotNetFiddle

Faire en boucle:
00: 00: 00.06

En boucle:
00: 00: 00.13

Pour boucle:
00: 00: 00.27

0
Mohit Dhawan

En ce qui concerne les boucles infinies, la boucle for(;;) est meilleure que while(1) puisque while évalue chaque fois la condition, mais là encore cela dépend du compilateur.

0
Ilian Zapryanov

Dépend de la langue et probablement de son compilateur, mais ils devraient être équivalents dans la plupart des langues. 

0
Randolpho

Je me demandais la même chose alors j'ai cherché sur Google et je me suis retrouvé ici ..__ J'ai fait un petit test en python (extrêmement simple) juste pour voir et voici ce que j'ai obtenu:

Pour:

def for_func(n = 0):
    for n in range(500):
        n = n + 1

python -m timeit "import for_func; for_func.for_func ()"> pour_func.txt

10000 boucles, meilleur de 3: 40.5 usec par boucle

Tandis que:

def while_func(n = 0):
    while n < 500:
        n = n + 1

python -m timeit "import while_func; while_func.while_func ()"> while_func.txt

10000 boucles, meilleur de 3: 45 usec par boucle

0
niclaslindgren

Peu importe lequel est le plus rapide. Si cela est important, comparez-le à l'aide de votre code réel et voyez par vous-même.

Les réponses à cette autre question pourraient également être utiles: Comment écrire du code plus efficace

0
David

Cela dépendra de la mise en œuvre linguistique de ladite boucle, du compilateur et de ce qui ne l’est pas. 

La plupart des compilateurs compileront exactement le même code exécutable, par exemple dans CIL (.NET). 

Source: vcsjones @ http://forums.asp.net/t/1041090.aspx

Quoi qu'il en soit, le corps de la boucle est l'endroit où le temps de traitement sera dépensé et non la façon dont vous l'itérisez. 

0
jfrobishow

Est-ce que techniquement, une boucle For n'est pas un Do?

Par exemple.

for (int i = 0; i < length; ++i)
{
   //Code Here.
}

serait...

int i = 0;
do 
{
  //Code Here.
} while (++i < length);

Je pourrais toutefois avoir tord...

Aussi quand il s'agit de pour les boucles. Si vous prévoyez de ne récupérer que des données et de ne jamais les modifier, vous devez utiliser un foreach. Si vous avez besoin des index réels pour une raison quelconque, vous devrez incrémenter et utiliser la boucle for régulière.

for (Data d : data)
{
       d.doSomething();
}

devrait être plus rapide que ...

for (int i = 0; i < data.length; ++i)
{
      data[i].doSomething();
}
0
Jeremy Trifilo