Słyszałem to już kilka razy. Czy pętle JavaScript są naprawdę szybsze podczas liczenia wstecz? Jeśli tak, to dlaczego? Widziałem kilka przykładów zestawu testów pokazujących, że odwrócone pętle są szybsze, ale nie mogę znaleźć żadnego wyjaśnienia, dlaczego!
Zakładam, że dzieje się tak, ponieważ pętla nie musi już oceniać właściwości za każdym razem, gdy sprawdza, czy jest zakończona, a jedynie sprawdza ostateczną wartość liczbową.
To znaczy
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
for
Pętla wsteczna jest szybsza, ponieważ zmienna sterująca pętli górnej granicy (hehe, dolnej granicy) nie musi być definiowana ani pobierana z obiektu; jest to stałe zero.Odpowiedzi:
To nie tak, że
i--
jest szybszy niżi++
. W rzeczywistości oba są równie szybkie.To, co wymaga czasu w rosnących pętlach, ocenia dla każdej
i
wielkości rozmiar tablicy. W tej pętli:Oceniasz
.length
tylko raz, kiedy deklarujeszi
, podczas gdy dla tej pętlioceniasz za
.length
każdym razemi
, gdy zwiększasz , sprawdzając, czyi <= array.length
.W większości przypadków nie powinieneś nawet martwić się o tego rodzaju optymalizację .
źródło
.length
określoną liczbę razy, czy też deklarować i definiować nową zmienną? W większości przypadków jest to przedwczesna (i błędna) optymalizacja, chyba żelength
ocena jest bardzo droga.0
jest szybszy do oceny niżarray.length
. Cóż, podobno..length
jest to deklaracja,for loop
czy nie.Ten facet porównał wiele pętli w javascript, w wielu przeglądarkach. Ma także zestaw testowy więc możesz sam je uruchomić.
We wszystkich przypadkach (chyba że brakowało mi jednego z moich odczytów) najszybsza pętla to:
źródło
--i
, musisz użyćvar current = arr[i-1];
wewnątrz pętli lub będzie ona wyłączona przez jeden ...Próbuję dać szeroki obraz tej odpowiedzi.
Poniższe myśli w nawiasach było moim przekonaniem, dopóki nie przetestowałem tego problemu:
[[W odniesieniu do języków niskiego poziomu, takich jak C / C ++ , kod jest kompilowany, dzięki czemu procesor ma specjalne polecenie skoku warunkowego, gdy zmienna ma wartość zero (lub niezerową).
Ponadto, jeśli zależy ci na takiej optymalizacji, możesz
++i
zamiast tego przejśći++
, ponieważ++i
jest to polecenie jednego procesora, a jednocześniei++
oznaczaj=i+1, i=j
.]]Naprawdę szybkie pętle można wykonać, rozwijając je:
Może być znacznie wolniejszy niż
ale przyczyny tego mogą być dość skomplikowane (aby wspomnieć, istnieją problemy związane z przetwarzaniem poleceń procesora i obsługą pamięci podręcznej w grze).
Pod względem języków wysokiego poziomu , takich jak JavaScript o które prosiłeś, możesz zoptymalizować rzeczy, jeśli polegasz na bibliotekach, wbudowanych funkcjach zapętlania. Pozwól im zdecydować, jak najlepiej to zrobić.
W związku z tym w JavaScript sugerowałbym użycie czegoś takiego
Jest również mniej podatny na błędy, a przeglądarki mają szansę zoptymalizować kod.
[UWAGA: nie tylko przeglądarki, ale także masz przestrzeń do łatwej optymalizacji, po prostu ponownie zdefiniuj
forEach
funkcję (zależnie od przeglądarki), aby korzystała z najnowszych najlepszych sztuczek! :) @AMK mówi w szczególnych przypadkach, że warto raczej użyćarray.pop
lubarray.shift
. Jeśli to zrobisz, połóż go za zasłoną. Największą nadwyżką jest dodanie opcjiforEach
wyboru algorytmu zapętlenia.]Ponadto, również w przypadku języków niskiego poziomu, najlepszą praktyką jest użycie inteligentnej funkcji bibliotecznej do złożonych, zapętlonych operacji, jeśli jest to możliwe.
Te biblioteki mogą również umieszczać różne elementy (wielowątkowe) za twoimi plecami, a także wyspecjalizowani programiści utrzymują je na bieżąco.
Zrobiłem trochę więcej kontroli i okazuje się, że w C / C ++, nawet dla operacji 5e9 = (50 000 x 100 000), nie ma różnicy między przechodzeniem w górę i w dół, jeśli testowanie odbywa się na stałej, jak mówi @alestanis. (Wyniki JsPerf są czasami niespójne, ale ogólnie rzecz biorąc mówią to samo: nie można zrobić dużej różnicy.)
Tak więc
--i
zdarza się, że jest to raczej „elegancka” rzecz. To tylko sprawia, że wyglądasz jak lepszy programista. :)Z drugiej strony, za rozwinięcie w tej sytuacji 5e9, zmniejszyłem mnie z 12 sekund do 2,5 sekundy, gdy przekroczyłem 10 sekund, i do 2,1 sekundy, kiedy przekroczyłem 20s. To było bez optymalizacji, a optymalizacja sprowadziła rzeczy do niezmierzonego krótkiego czasu. :) (Rozwijanie można wykonać na swój sposób powyżej lub przy użyciu
i++
, ale to nie przyspiesza działania w JavaScript.)Podsumowując: zachowaj
i--
/i++
i++i
/i++
różnice w rozmowach kwalifikacyjnych, trzymaj sięarray.forEach
lub innych złożonych funkcji bibliotecznych, jeśli są dostępne. ;)źródło
array.each(...)
. Nie sądzę, żeby próbowali eksperymentować z rozpętaniem zwykłych pętli for.+1
zdobyćGreat Answer
odznakę. Naprawdę świetna odpowiedź. :)i--
jest tak szybki jaki++
Poniższy kod jest tak szybki jak Twój, ale używa dodatkowej zmiennej:
Zaleca się, aby NIE oceniać wielkości tablicy za każdym razem. W przypadku dużych tablic widać spadek wydajności.
źródło
for (var i=0, up=Things.length; i<up; i++) {}
Ponieważ jesteś zainteresowany tym tematem, zapoznaj się z postem na blogu Grega Reimera na temat testu porównawczego pętli JavaScript. Jaki jest najszybszy sposób na kodowanie pętli w JavaScript? :
Możesz także wykonać test wydajności w pętli , otwierając
https://blogs.oracle.com/greimer/resource/loop-test.html
(nie działa, jeśli JavaScript jest zablokowany w przeglądarce na przykład przez NoScript ).EDYTOWAĆ:
Nowszy test porównawczy stworzony przez Milana Adamowskiego można wykonać tutaj w czasie wykonywania dla różnych przeglądarek.
Do testowania w przeglądarce Firefox 17.0 na Mac OS X 10.6 dostałem następującą pętlę:
najszybciej jak poprzedza:
źródło
To nie jest
--
lub++
jest to porównać działanie. Ze--
można użyć porównania z 0, natomiast ze++
trzeba porównać ją z długością. W procesorze porównanie z zerem jest zwykle dostępne, natomiast porównanie z skończoną liczbą całkowitą wymaga odjęcia.a++ < length
jest właściwie skompilowany jako
Po skompilowaniu zajmuje to więcej czasu procesorowi.
źródło
Krótka odpowiedź
W przypadku normalnego kodu, szczególnie w języku wysokiego poziomu, takim jak JavaScript , nie ma różnicy w wydajności w
i++
ii--
.Kryterium wydajności to użycie w
for
pętli i porównanie .To dotyczy wszystkich języków wysokiego poziomu , a to przede wszystkim niezależny od stosowania JavaScript. Wyjaśnieniem jest wynikowy kod asemblera w dolnej linii.
Szczegółowe wyjaśnienie
Różnica wydajności może wystąpić w pętli. Tło jest takie, że na poziomie kodu asemblera widać, że:
compare with 0
to tylko jedna instrukcja, która nie wymaga dodatkowego rejestru.To porównanie jest wydawane przy każdym przejściu pętli i może spowodować wymierną poprawę wydajności.
zostanie przetworzony na pseudo kod taki jak ten:
Zauważ, że 0 jest dosłowne lub innymi słowy stałą wartością.
zostanie przetworzony na pseudo kod taki jak ten (zakłada się normalną optymalizację interpretera):
Zauważ, że end jest zmienną wymagającą rejestru procesora . Może to wywołać dodatkową zamianę rejestru w kodzie i wymaga droższej instrukcji porównania w
if
instrukcji.Tylko moje 5 centów
W przypadku języka wysokiego poziomu czytelność, która ułatwia konserwację, jest ważniejsza jako niewielka poprawa wydajności.
Zwykle lepsza jest klasyczna iteracja od początku do końca tablicy .
Szybsza iteracja od końca tablicy do początku powoduje prawdopodobnie niepożądaną odwróconą sekwencję.
Post Scriptum
Jak zadano w komentarzu: Różnica
--i
ii--
jest w oceniei
przed lub po zmniejszanie.Najlepszym wyjaśnieniem jest wypróbowanie ;-) Oto przykład Bash .
źródło
--i
ai--
także?Widziałem to samo zalecenie w Sublime Text 2.
Jak już powiedziano, głównym ulepszeniem nie jest ocena długości tablicy przy każdej iteracji w pętli for. Jest to dobrze znana technika optymalizacji i szczególnie wydajna w JavaScript, gdy tablica jest częścią dokumentu HTML (robi to
for
dla wszystkichli
elementów).Na przykład,
for (var i = 0; i < document.getElementsByTagName('li').length; i++)
jest znacznie wolniejszy niż
for (var i = 0, len = document.getElementsByTagName('li').length; i < len; i++)
Z tego, co stoję, główną poprawą formy w pytaniu jest to, że nie deklaruje dodatkowej zmiennej (
len
w moim przykładzie)Ale jeśli mnie zapytasz, cała sprawa nie polega na optymalizacji
i++
vsi--
, ale na tym, że nie musisz oceniać długości tablicy przy każdej iteracji (możesz zobaczyć test porównawczy na jsperf ).źródło
Nie sądzę, że sensownie jest powiedzieć, że
i--
jest szybszy niżi++
w JavaScript.Przede wszystkim zależy to całkowicie od implementacji silnika JavaScript.
Po drugie , pod warunkiem, że najprostsze konstrukcje JIT i przetłumaczone na instrukcje natywne, wtedy
i++
vsi--
będzie całkowicie zależeć od procesora, który je wykonuje. Oznacza to, że na ARM (telefony komórkowe) szybciej jest zejść do zera, ponieważ zmniejszanie i porównywanie do zera są wykonywane w jednej instrukcji.Prawdopodobnie myślałeś, że jeden był lepszy niż drugi, ponieważ tak sugeruje
ale sugerowany sposób nie polega na tym, że jeden jest szybszy od drugiego, ale po prostu dlatego, że piszesz
następnie przy każdej iteracji
array.length
trzeba było oceniać (być może mądrzejszy silnik JavaScript mógłby stwierdzić, że pętla nie zmieni długości tablicy). Mimo że wygląda na prostą instrukcję, w rzeczywistości jest to funkcja wywoływana pod maską przez silnik JavaScript.Innym powodem, dla
i--
którego można uznać to za „szybsze”, jest to, że silnik JavaScript musi przydzielić tylko jedną zmienną wewnętrzną do sterowania pętlą (zmienną dovar i
). W porównaniu do array.length lub jakiejś innej zmiennej, musiała istnieć więcej niż jedna zmienna wewnętrzna do sterowania pętlą, a liczba zmiennych wewnętrznych jest ograniczoną zaletą silnika JavaScript. Im mniej zmiennych jest używanych w pętli, tym większa szansa, że JIT ma szansę na optymalizację. Dlategoi--
można go uznać za szybszy ...źródło
array.length
oceny. Długość nie jest obliczana, gdy się do niej odwołujesz. (To tylko właściwość, która jest ustawiana za każdym razem, gdy indeks tablicy jest tworzony lub zmieniany ). Gdy występują dodatkowe koszty, dzieje się tak, ponieważ silnik JS nie zoptymalizował łańcucha wyszukiwania dla tej nazwy.getLength(){return m_length; }
ponieważ wiąże się to z utrzymaniem porządku. Ale jeśli spróbujesz pomyśleć wstecz: byłoby całkiem genialnie napisać implementację tablicy, w której długość musiałaby być rzeczywiście obliczona :)length
Musi być aktualizowana natychmiast, gdy właściwość-that-is-an-array-indeks jest dodane lub zmienione.dec/jnz
vsinc eax / cmp eax, edx / jne
.Ponieważ żadna z pozostałych odpowiedzi nie wydaje się odpowiadać na konkretne pytanie (ponad połowa z nich pokazuje przykłady C i omawia języki niższego poziomu, twoje pytanie dotyczy JavaScript), postanowiłem napisać własny.
Więc proszę:
Prosta odpowiedź:
i--
jest na ogół szybsza, ponieważ nie musi uruchamiać porównania do 0 za każdym razem, wyniki testów dla różnych metod są poniżej:Wyniki testu: „Jak udowodniono” w tym jsPerf,
arr.pop()
jest to jak dotąd najszybsza pętla. Ale, koncentrując się na--i
,i--
,i++
a++i
jak pytasz w swoim pytaniu, oto jsPerf (są z wielu jsPerf'S, patrz źródła poniżej) Wyniki podsumowane:--i
ii--
są takie same w Firefox, podczas gdyi--
jest szybszy w Chrome.W Chrome podstawowym pętli for (
for (var i = 0; i < arr.length; i++)
) jest szybsza niżi--
i--i
podczas gdy Firefox jest wolniejszy.Zarówno w Chrome, jak i Firefox pamięć podręczna
arr.length
jest znacznie szybsza w Chrome o około 170 000 operacji na sekundę.Bez znaczącej różnicy,
++i
jest szybszy niżi++
w większości przeglądarek, AFAIK, nigdy nie jest odwrotnie w żadnej przeglądarce.Krótsze podsumowanie:
arr.pop()
jak dotąd najszybsza pętla; dla specjalnie wymienionych pętli,i--
jest najszybszą pętlą.Źródła: http://jsperf.com/fastest-array-loops-in-javascript/15 , http://jsperf.com/ipp-vs-ppi-2
Mam nadzieję, że to odpowiada na twoje pytanie.
źródło
pop
test wydaje się dość szybki, ponieważ zmniejsza rozmiar tablicy do 0 dla większości pętli - o ile wiem. Jednak, aby upewnić się, że wszystko jest w porządku, zaprojektowałem ten jsperf, aby tworzył tablicę w taki sam sposób przy każdym teście - który wydaje się.shift()
być zwycięzcą dla moich kilku przeglądarek - ale nie tego bym się spodziewał :) jsperf.com /++i
: DZależy to od umieszczenia tablicy w pamięci i współczynnika trafień stron pamięci podczas uzyskiwania dostępu do tej tablicy.
W niektórych przypadkach dostęp do elementów tablicy w kolejności kolumn jest szybszy niż w kolejności wierszy ze względu na wzrost współczynnika trafień.
źródło
Ostatni raz o tym myślałem podczas pisania zestawu 6502 (8 bitów, tak!). Dużym zyskiem jest to, że większość operacji arytmetycznych (zwłaszcza dekrementów) aktualizuje zestaw flag, jedną z nich był
Z
wskaźnik „osiągnął zero”.Tak więc na końcu pętli wykonałeś dwie instrukcje:
DEC
(zmniejszenie) iJNZ
(skok, jeśli nie zero), porównanie nie jest potrzebne!źródło
i--
vsi++
jest to, że w pierwszym przypadku nie wprowadza się dodatkowych zmiennych kontrolnych w zakresie pętli. Zobacz moją odpowiedź poniżej ...dec/jnz
zamiastinc/cmp/jne
dla przypadku x86. Nie zobaczysz, że pusta pętla działa szybciej (oba nasycą przepustowość gałęzi), ale odliczanie nieznacznie zmniejsza obciążenie pętli. Obecne moduły wstępnego Intel Intel nie przeszkadzają wzorce dostępu do pamięci, które idą w kolejności malejącej. Myślę, że starsze procesory mogłyby śledzić 4 strumienie wstecz i 6 lub 10 strumieni w przód, IIRC.Można to wyjaśnić JavaScriptem (i wszystkimi językami), które ostatecznie zamieniają się w kody operacyjne do uruchomienia na CPU. Procesory zawsze mają jedną instrukcję porównywania z zerem, co jest cholernie szybkie.
Nawiasem mówiąc, jeśli możesz zagwarantować , że
count
zawsze>= 0
, możesz uprościć:źródło
Nie zależy to od znaku
--
lub++
, ale zależy od warunków stosowanych w pętli.Na przykład: Twoja pętla jest szybsza, jeśli zmienna ma wartość statyczną, niż wtedy, gdy pętla sprawdza warunki za każdym razem, takie jak długość tablicy lub inne warunki.
Ale nie martw się o tę optymalizację, ponieważ tym razem jej działanie jest mierzone w nanosekundach.
źródło
for(var i = array.length; i--; )
nie jest dużo szybszy. Ale po wymianiearray.length
zsuper_puper_function()
, które mogą być znacznie szybciej (ponieważ to się nazywa w każdej iteracji). To jest różnica.Jeśli zamierzasz to zmienić w 2014 roku, nie musisz myśleć o optymalizacji. Jeśli zamierzasz to zmienić za pomocą „Wyszukaj i zamień”, nie musisz myśleć o optymalizacji. Jeśli nie masz czasu, nie musisz myśleć o optymalizacji. Ale teraz masz czas, aby się nad tym zastanowić.
PS:
i--
nie jest szybszy niżi++
.źródło
Krótko mówiąc: nie ma absolutnie żadnej różnicy w robieniu tego w JavaScript.
Przede wszystkim możesz to przetestować samodzielnie:
jsperf - jest doskonałą platformą do wszelkiego rodzaju testów wydajności w JavaScript .
http://jsperf.com/inc-vs-dec-2
Nie tylko możesz przetestować i uruchomić dowolny skrypt w dowolnej bibliotece JavaScript, ale masz również dostęp do całej gamy wcześniej napisanych skryptów, a także możesz zobaczyć różnice między czasem wykonania w różnych przeglądarkach na różnych platformach.
O ile widać, nie ma różnicy między wydajnością w dowolnym środowisku.
Jeśli chcesz poprawić wydajność skryptu, możesz spróbować:
var a = array.length;
instrukcję, aby nie obliczać jej wartości za każdym razem w pętliMusisz jednak zrozumieć, że poprawa, którą możesz uzyskać, będzie tak nieznaczna, że przeważnie nie powinieneś się tym przejmować.
Moja własna opinia, dlaczego pojawiło się takie nieporozumienie (Dec vs. Inc)
Dawno, dawno temu istniała wspólna instrukcja maszyny, DSZ (Decrement and Skip on Zero). Ludzie, którzy programowali w asemblerze, używali tej instrukcji do implementacji pętli w celu zapisania rejestru. Teraz te starożytne fakty są przestarzałe i jestem prawie pewien, że nie uzyskasz żadnej poprawy wydajności w żadnym języku za pomocą tej pseudopoprawki.
Myślę, że jedynym sposobem, w jaki taka wiedza może się propagować w naszych czasach, jest czytanie kodu osoby innej osoby. Zobacz taką konstrukcję i zapytaj, dlaczego została wdrożona, a tutaj odpowiedź: „poprawia wydajność, ponieważ porównuje do zera”. Oszołomiłeś się wyższą wiedzą o swoim współpracowniku i myślisz, że możesz go wykorzystać, aby być mądrzejszym :-)
źródło
array.length
niekoniecznie wiąże się z obniżeniem wydajności, po prostu dlatego, że maszyna wirtualna JS jest wystarczająco inteligentna, aby stwierdzić, czy tablica nie jest modyfikowana przez ciało pętli. Zobacz moją odpowiedź poniżej.Zrobiłem porównanie na jsbench .
Jak zauważył Alestani, jedną rzeczą, która wymaga czasu w rosnących pętlach, jest ocena, dla każdej iteracji, rozmiaru tablicy. W tej pętli:
oceniasz za
.length
każdym razem, gdy zwiększaszi
. W tym:oceniasz
.length
tylko raz, kiedy deklarujeszi
. W tym:porównanie jest niejawne, dzieje się to tuż przed zmniejszeniem
i
, a kod jest bardzo czytelny. Jednak to, co może zrobić niesamowitą różnicę, to to, co wkładasz do pętli.Pętla z wywołaniem funkcji (zdefiniowanym gdzie indziej):
Pętla z wbudowanym kodem:
Jeśli możesz wstawić kod zamiast wywoływać funkcję bez utraty czytelności, możesz mieć pętlę rzędu wielkości szybciej!
Uwaga : ponieważ przeglądarka staje się dobra w wprowadzaniu prostych funkcji, tak naprawdę zależy to od stopnia skomplikowania kodu. Więc profiluj przed optymalizacją, ponieważ
Ale pamiętaj:
źródło
Sposób, w jaki to robisz, nie jest szybszy (poza tym, że jest to pętla na czas nieokreślony, myślę, że chciałeś to zrobić
i--
.Jeśli chcesz przyspieszyć, wykonaj następujące czynności:
oczywiście nie zauważyłbyś tego w tak małej pętli. Powodem jest szybsze, ponieważ zmniejszasz i sprawdzając, czy jest to „prawda” (zmienia się na „fałsz”, gdy osiągnie 0)
źródło
(i = 10; i--;)
Czasami wprowadzenie niewielkich zmian w sposobie pisania kodu może mieć duży wpływ na szybkość jego działania. Jednym z obszarów, w którym niewielka zmiana kodu może znacząco wpłynąć na czas wykonania, jest pętla for przetwarzająca tablicę. Tam, gdzie tablica zawiera elementy na stronie internetowej (takie jak przyciski opcji), zmiana ma największy efekt, ale nadal warto zastosować tę zmianę, nawet jeśli tablica jest wewnętrzna w kodzie JavaScript.
Konwencjonalny sposób kodowania pętli for w celu przetworzenia tablicy lis w następujący sposób:
Problem polega na tym, że ocena długości tablicy za pomocą myArray.length wymaga czasu, a sposób, w jaki zakodowaliśmy pętlę, oznacza, że ta ocena musi być przeprowadzana za każdym razem wokół pętli. Jeśli tablica zawiera 1000 elementów, długość tablicy zostanie oszacowana 1001 razy. Jeśli spojrzeliśmy na przyciski opcji i mielibyśmy myForm.myButtons.length, wówczas ocena zajmie jeszcze więcej czasu, ponieważ odpowiednia grupa przycisków w określonym formularzu musi najpierw zostać zlokalizowana, zanim długość będzie można oszacować za każdym razem wokół pętli.
Oczywiście nie oczekujemy zmiany długości tablicy podczas jej przetwarzania, więc wszystkie te ponowne obliczenia długości tylko niepotrzebnie zwiększają czas przetwarzania. (Oczywiście, jeśli masz kod w pętli, który dodaje lub usuwa wpisy tablicy, rozmiar tablicy może się zmieniać między iteracjami, więc nie możemy zmienić kodu, który ją testuje)
To, co możemy zrobić, aby to poprawić w przypadku pętli, w której rozmiar jest stały, to ocenić długość raz na początku pętli i zapisać ją w zmiennej. Następnie możemy przetestować zmienną, aby zdecydować, kiedy zakończyć pętlę. Jest to o wiele szybsze niż ocenianie długości tablicy za każdym razem, szczególnie gdy tablica zawiera więcej niż kilka wpisów lub jest częścią strony internetowej.
Kod do wykonania tego jest:
Więc teraz oceniamy rozmiar tablicy tylko raz i testujemy licznik pętli na zmiennej, która przechowuje tę wartość za każdym razem wokół pętli. Dostęp do tej dodatkowej zmiennej jest znacznie szybszy niż ocena rozmiaru tablicy, dzięki czemu nasz kod będzie działał znacznie szybciej niż wcześniej. W naszym skrypcie mamy tylko jedną dodatkową zmienną.
Często nie ma znaczenia, w jakiej kolejności przetwarzamy tablicę, dopóki wszystkie wpisy w tablicy zostaną przetworzone. W takim przypadku możemy nieco przyspieszyć nasz kod, usuwając dodatkową zmienną, którą właśnie dodaliśmy, i przetwarzając tablicę w odwrotnej kolejności.
Końcowy kod, który przetwarza naszą tablicę w najbardziej efektywny możliwy sposób, to:
Ten kod wciąż ocenia rozmiar tablicy tylko raz na początku, ale zamiast porównywać licznik pętli ze zmienną, porównujemy ją ze stałą. Ponieważ stała jest jeszcze bardziej efektywna w dostępie niż zmienna, a ponieważ mamy jedną mniej instrukcji przypisania niż wcześniej, nasza trzecia wersja kodu jest teraz nieco bardziej wydajna niż druga wersja i znacznie wydajniejsza niż pierwsza.
źródło
++
vs.--
nie ma znaczenia, ponieważ JavaScript jest językiem interpretowanym, a nie skompilowanym. Każda instrukcja tłumaczy na więcej niż jeden język maszynowy i nie powinieneś przejmować się krwawymi szczegółami.Ludzie, którzy mówią o używaniu
--
(lub++
) do efektywnego korzystania z instrukcji montażu, są w błędzie. Te instrukcje dotyczą arytmetyki liczb całkowitych, aw JavaScript nie ma liczb całkowitych, tylko liczby .Powinieneś napisać czytelny kod.
źródło
W wielu przypadkach nie ma to w zasadzie nic wspólnego z faktem, że procesory mogą porównywać do zera szybciej niż inne porównania.
Wynika to z faktu, że tylko kilka silników Javascript (tych z listy JIT) faktycznie generuje kod języka maszynowego.
Większość silników Javascript tworzy wewnętrzną reprezentację kodu źródłowego, który następnie interpretuje (aby dowiedzieć się, jak to jest, spójrz do dolnej części tej strony na SpiderMonkey w Firefoksie ). Ogólnie rzecz biorąc, jeśli fragment kodu robi praktycznie to samo, ale prowadzi do prostszej wewnętrznej reprezentacji, będzie działał szybciej.
Należy pamiętać, że przy prostych zadaniach, takich jak dodawanie / odejmowanie jednej zmiennej lub porównywanie zmiennej z czymś, narzut tłumacza przechodzący z jednej wewnętrznej „instrukcji” do drugiej jest dość wysoki, więc mniej „instrukcji”, które są używane wewnętrznie przez silnik JS, tym lepiej.
źródło
Cóż, nie wiem o JavaScript, tak naprawdę powinna to być kwestia ponownej oceny długości tablicy i być może coś wspólnego z tablicami asocjacyjnymi (jeśli tylko zmniejszysz, jest mało prawdopodobne, że nowe wpisy będą musiały zostać przydzielone - jeśli tablica jest gęsta, to znaczy. ktoś może to zoptymalizować).
W asemblerze niskiego poziomu istnieje instrukcja pętli zwana DJNZ (zmniejszanie i przeskakiwanie, jeśli nie jest zero). Tak więc zmniejszenie i skok są w jednej instrukcji, co sprawia, że jest to prawdopodobnie nieco szybsze niż INC i JL / JB (przyrost, skok, jeśli mniej niż / skok, jeśli poniżej). Również porównanie z zerem jest łatwiejsze niż porównanie z inną liczbą. Ale to wszystko jest naprawdę marginalne i zależy również od architektury docelowej (może to mieć znaczenie np. W Uzbrojeniu w smartfonie).
Nie spodziewałbym się, że różnice niskiego poziomu będą miały tak duży wpływ na języki interpretowane, po prostu nie widziałem DJNZ wśród odpowiedzi, więc pomyślałem, że podzielę się ciekawą myślą.
źródło
DJNZ
przypomnienia , jest instrukcją w ISA 8051 (z80). x86 madec/jnz
zamiast tegoinc/cmp/jne
i najwyraźniej ramię ma coś podobnego. Jestem prawie pewien, że nie jest to przyczyną różnicy w Javascript; to z konieczności ewaluacji więcej w pętli.jest używany do powiedzenia, że --i był szybszy (w C ++), ponieważ jest tylko jeden wynik, wartość zmniejszany. i-- musi zapisać zmniejszoną wartość z powrotem do i, a także zachować oryginalną wartość jako wynik (j = i--;). W większości kompilatorów wykorzystywało to raczej dwa rejestry niż jeden, co może powodować konieczność zapisania innej zmiennej w pamięci, a nie zachowania jej jako zmiennej rejestru.
Zgadzam się z tymi, którzy powiedzieli, że w dzisiejszych czasach nie ma znaczenia.
źródło
W bardzo prostych słowach
„i-- i i ++. Właściwie oba zajmują ten sam czas”.
ale w tym przypadku, gdy wykonujesz operację przyrostową .. procesor ocenia długość. za każdym razem, gdy zmienna jest zwiększana o 1, aw przypadku zmniejszenia wartości .. szczególnie w tym przypadku, ocenia długość. tylko raz, aż otrzymamy 0.
źródło
Po pierwsze
i++
ii--
zajmij dokładnie ten sam czas w dowolnym języku programowania, w tym JavaScript.Poniższy kod zajmuje dużo czasu.
Szybki:
Powolny:
Dlatego poniższy kod również zajmuje inny czas.
Szybki:
Powolny:
PS Slow działa wolno tylko w kilku językach (silniki JavaScript) ze względu na optymalizację kompilatora. Najlepszym sposobem jest użycie „<” zamiast „<=” (lub „=”) i „--i” zamiast „i--” .
źródło
I- lub i ++ nie zużywają dużo czasu. Jeśli zagłębisz się głęboko w architekturę procesora,
++
jest to szybsze niż--
, ponieważ--
operacja uzupełni uzupełnienie 2, ale dzieje się to w sprzęcie, dzięki czemu jest szybka i nie ma większej różnicy między tymi,++
a--
także te operacje są brane pod uwagę najmniej czasu zużywanego przez procesor.Pętli for przebiega tak:
<
,>
,<=
, itd.Więc,
obliczy długość tablicy tylko raz na początku i nie jest to dużo czasu, ale
obliczy długość każdej pętli, więc zajmie to dużo czasu.
źródło
var i = Things.length - 1; i >= 0; i--
też obliczy długość 1 raz.--
operacja dopełni uzupełnienie 2”, ale zakładam, że oznacza to, że coś zaprzeczy. Nie, nie neguje niczego w żadnej architekturze. Odejmowanie 1 jest tak proste, jak dodawanie 1, po prostu tworzysz obwód, który pożycza, a nie przenosi.Najlepszym podejściem do odpowiedzi na tego rodzaju pytanie jest wypróbowanie go. Skonfiguruj pętlę liczącą milion iteracji lub cokolwiek innego i zrób to na dwa sposoby. Czas obu pętli i porównaj wyniki.
Odpowiedź prawdopodobnie zależeć będzie od używanej przeglądarki. Niektóre będą miały inne wyniki niż inne.
źródło
Uwielbiam to, wiele ocen, ale brak odpowiedzi: D
Po prostu porównanie z zerem jest zawsze najszybszym porównaniem
Tak więc (a == 0) jest w rzeczywistości szybsze w zwracaniu wartości True niż (a == 5)
Jest mały i mało znaczący, a przy 100 milionach wierszy w kolekcji jest mierzalny.
tzn. w pętli możesz powiedzieć, gdzie i <= array.length i zwiększać i
w dolnej pętli możesz powiedzieć, gdzie i> = 0 i zamiast tego zmniejszać i.
Porównanie jest szybsze. Nie „kierunek” pętli.
źródło
POMÓŻ INNYM UNIKAĆ SŁUCHAWKI --- ZAGŁOSUJ TO!
Najpopularniejsza odpowiedź na tej stronie nie działa w przeglądarce Firefox 14 i nie przechodzi przez jsLinter. Pętle „while” wymagają operatora porównania, a nie przypisania. Działa na Chrome, Safari, a nawet np. Ale umiera w firefoxie.
TO ZŁOŻYŁO SIĘ!
TO DZIAŁA! (działa na Firefoksie, przekazuje jsLinter)
źródło
while (i--)
i które działają w wielu przeglądarkach. Czy w twoim teście mogło być coś dziwnego? Czy używasz wersji beta przeglądarki Firefox 14?To tylko przypuszczenie, ale może dlatego, że procesorowi łatwiej jest porównać coś z 0 (i> = 0) zamiast z inną wartością (i <Things.length).
źródło