2010-09-02 18 views
25

Można uzyskać taką samą moc z for i while Pętle:Która pętla jest szybsza, kiedy lub dla?

Podczas:

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

Dla:

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

Ale który z nich jest szybszy?

+7

Zmierz je, jeśli chcesz (ale prawdopodobnie są równe). –

+3

Założę się, że generują dokładnie ten sam kod bajtowy. – zwol

+5

'for' w większości języków to cukier syntaktyczny dla równoważnej pętli' while', która z kolei jest syntaktycznym cukrem dla zestawu etykiet i 'gotos' down w złożeniu lub IL. Biorąc pod uwagę efektywną implementację specyfikacji językowej, będą one mniej więcej równe. Niektóre języki zawierają wewnętrzne "komentarze" podające wskazówki dla dekompilatorów/reflektorów na temat wyglądu oryginalnego kodu, co będzie miało znikomy wpływ na wydajność. Myślę, że przekonasz się, że największe różnice czasu wykonania między nimi są nieodłączne w planowaniu systemu operacyjnego. – KeithS

Odpowiedz

20

To oczywiście zależy od konkretnej implementacji interpretera/kompilatora określonego języka.

Teoretycznie, każda rozsądna implementacja będzie prawdopodobnie w stanie zrealizować jedną pod względem drugiej, jeśli jest szybsza, więc różnica powinna być co najmniej nieistotna.

Oczywiście zakładałem, że while i for zachowują się tak jak w języku C i podobnych językach. Można utworzyć język z zupełnie różnych semantyki dla while i for

0

zależy od języka i najprawdopodobniej jego kompilatora, ale powinny one być równoważne w większości języków.

1

Powinny być równe. Pętla for, którą napisałeś, wykonuje dokładnie to samo, co pętla while: ustawienie $i=0, drukowanie $i i zwiększanie $i na końcu pętli.

3

Gdyby to był program C, nie powiedziałbym nic. Kompilator wypisze dokładnie ten sam kod. Ponieważ nie jest, mówię, zmierzyć. W rzeczywistości nie chodzi o to, która konstrukcja pętli jest szybsza, ponieważ jest to niewielkie oszczędności czasu. Chodzi o to, która konstrukcja pętli jest łatwiejsza do utrzymania. W przypadku, gdy pokazałeś, pętla for jest bardziej odpowiednia, ponieważ to właśnie oczekują inni programiści (w tym przyszły ty, mam nadzieję).

0

Nie powinno mieć znaczenia, które jest szybsze. Jeśli ma to znaczenie, przetestuj go, używając prawdziwego kodu i przekonaj się sam.

Odpowiedzi na to drugie pytanie może być przydatna także: How to write more efficient code

0

To zależy od implementacji języka wspomnianej pętli, kompilator, a co nie.

Większość kompilatorów skompiluje się do tego samego kodu wykonywalnego, na przykład w CIL (.NET), który definitywnie robią.

Źródło: vcsjones @http://forums.asp.net/t/1041090.aspx

czy inaczej, ciało pętli jest, gdy czas przetwarzania nie zostaną wydane sposób iteracyjne.

3

Ustaw iteracje pętli na 10.000.

Znajdź czas w milisekundach> Uruchom pętlę> znajdź czas w milisekundach i odejmij pierwszy licznik czasu.

Zrób to dla obu kodów, niezależnie od tego, która z nich ma najmniejszą liczbę milisekund, która działa szybciej. Możesz wielokrotnie uruchomić test i wyedytować je, aby zmniejszyć prawdopodobieństwo wpływu procesów w tle na test.

Prawdopodobnie na obu pojawi się naprawdę podobny czas, ale jestem zainteresowany tym, czy ktoś jest zawsze odrobinę szybszy.

+0

Co zaskakujące, dla PHP pętla while była o 0,08 sekundy szybsza niż 10 milionów iteracji. –

4

Jak powiedzieli inni, każdy kompilator warty swojej soli wygeneruje praktycznie identyczny kod. Jakakolwiek różnica w wydajności jest znikoma - jesteś mikrooptymalizacją.

Prawdziwe pytanie brzmi: co jest bardziej czytelne? I to jest pętla for (przynajmniej IMHO).

5

znaleźć najszybciej pętli while zwrotnego, na przykład:

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

w C#, po Dla pętli nieznacznie szybciej.

Dla średniej pętli około 2,95 do 3,02 ms.

Pętla While wynosiła średnio od 3,05 do 3,37 ms.

Szybka aplikacja trochę konsola do udowodnienia:

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"); 
     } 
    } 
+1

Może się zdarzyć, że gdy kompilator działał w pętli, wykonał inne zadanie w tle, również bcz, które trwało nieco dłużej. Jak się upewniłeś o tych rzeczach? –

+0

Ja nie. To nie był eksperyment w czystym pomieszczeniu. Przeprowadziłem ten sam proces wiele razy i konsekwentnie były podobne wyniki. Więc to by mi powiedziało o prawdopodobieństwie jakiegoś zadania w tle losowo wpływającego na czasy tylko dla Pętli Podczas gdy była minimalna. – Shane

+1

Co jest szybsze, zależy od tego, co robisz. [Tutaj jest porównanie blogów, które porównuje iteracje] (http://cc.davelozinski.com/c-sharp/for-vs-foreach-vs-while) na wielu rodzajach obiektów, takich jak DataRows i obiekty niestandardowe, w tym również wydajność konstrukcji pętli While, a nie tylko konstrukcje for i foreach. –

1

Niektóre kompilatory optymalizujące będą mogli zrobić lepiej odwijanie pętli z pętli for, ale na to, że jeśli robisz coś, co może być rozwijana, A Kompilator wystarczająco inteligentny, aby go rozwinąć, jest prawdopodobnie również wystarczająco inteligentny, aby zinterpretować stan pętli pętli while jako coś, co można również rozwinąć.

0

Czy nie jest dla pętli technicznie a Do While?

E.g.

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

byłoby ...

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

mogę się mylić, choć ...

Również jeśli chodzi o pętle. Jeśli planujesz tylko pobierać dane i nigdy nie modyfikować danych, powinieneś użyć foreach. Jeśli potrzebujesz konkretnych indeksów z jakiegoś powodu, musisz zwiększyć, więc powinieneś użyć zwykłej pętli for.

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

powinno być szybsze niż ...

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

Pętla 'for' nie jest w ogóle pętlą' do'. Jeden test przed wykonaniem pętli i pozostałe testy po. Duża różnica. –

0

zastanawiałem się to samo, więc google i skończyło się tutaj. zrobiłem mały test w python (bardzo prosty), by zobaczyć, i to, co mam:

Dla:

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

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

10000 pętli, najlepiej 3: 40.5 ZS na pętlę

przy czym:

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

pyton -m timeit "importowej while_func; while_func.while_func()"> while_func.txt

10000 pętle, Najlepszy 3: 45 użyt. W pętli

1

Użyłem pętli for i while na bryle maszyna testowa (nie działają żadne niestandardowe procesy w tle). Uruchomiłem for loop vs while loop, ponieważ odnosi się do zmiany właściwości stylu 10 000 <button> węzłów.

Test prowadzono kolejno 10 razy, z 1 biegu timed się do 1500 milisekund przed wykonaniem:

tutaj jest bardzo prosty javascript że wykonany w tym celu

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); 
}); 

tutaj są wyniki, które otrzymałem:

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 

Oto demo link

Aktualizacja

oddzielny test I przeprowadzono znajduje się poniżej, który realizuje 2 inaczej zapisane czynnikowe algorytmów 1 za pomocą pętli, a drugi za pomocą pętli while.

Oto kod:

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); 
})(); 

A wyniki dla silni odniesienia:

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 

Wniosek: Bez względu na wielkość próby lub specyficzny rodzaj zadania testowane, nie ma wyraźnego zwycięzcy pod względem wydajności między pętlą while i for. Testowanie wykonane na komputerze MacAir z systemem OS X Mavericks na Chrome evergreen.

+0

Więc jaki jest twój wniosek? – Bergi

+0

Zwiększę wielkość próbki i zamiast tego użyję algorytmu do załadowania procesu. Mam nadzieję, że wyniki będą wtedy bardziej rozstrzygające. Po prostu szukam poprawnej implementacji, aby odpowiednio ją rozszerzyć. –

+1

@Bergi Bez wyraźnego zwycięzcy po kolejnych testach –

0

chodzi o nieskończonej pętli for(;;) pętla jest lepsza niż while(1) od while ocenia za każdym razem, pod warunkiem jednak ponownie to zależy od kompilatora.

Powiązane problemy