Döngüler tersine gerçekten daha mı hızlı?


268

Bunu birkaç kez duydum. Geriye doğru sayarken JavaScript döngüleri gerçekten daha mı hızlı? Öyleyse neden? Ters döngülerin daha hızlı olduğunu gösteren birkaç test paketi örneği gördüm, ancak nedenine ilişkin herhangi bir açıklama bulamıyorum!

Ben döngü artık bitmiş olup olmadığını görmek için kontrol her zaman bir özellik değerlendirmek zorunda değildir ve sadece son sayısal değere karşı denetler çünkü varsayıyorum.

yani

for (var i = count - 1; i >= 0; i--)
{
  // count is only evaluated once and then the comparison is always on 0.
}

6
hehe. süresiz olarak alacaktır. deneyin i--
StampedeXV

5
Geriye doğru fordöngü daha hızlıdır çünkü üst sınır (hehe, alt sınır) döngü kontrol değişkeninin bir nesneden tanımlanması veya getirilmesi gerekmez; sabit bir sıfırdır.
Josh Stodola

88
Orada gerçek fark . Yerel döngü yapıları her zaman çok hızlı olacaktır . Performansları için endişelenme.
James Allardice

24
@Afshin: Bunun gibi sorular için lütfen bize referansta bulunduğunuz makaleleri gösterin .
Yörüngedeki Hafiflik Yarışları

22
Çok düşük uçlu ve pille çalışan cihazlar için temel olarak fark vardır. Farklar, i-- ile döngü sonu için 0 ile karşılaştırırken, i ++ ile sayı> 0 ile karşılaştırırsınız. Performans farkının 20 nanosaniye (cmp balta, 0 vs. cmp balta gibi) olduğuna inanıyorum. , bx) - hiçbir şey ama saniyede binlerce kez döngü yaparsanız, neden her biri için 20 nanosaniye
kazanmıyorsunuz

Yanıtlar:


902

Bundan i--daha hızlı değil i++. Aslında ikisi de eşit derecede hızlı.

Yükselen döngülerde zaman alan şey, her ibiri için dizinizin boyutunu değerlendirmektir . Bu döngüde:

for(var i = array.length; i--;)

.lengthBeyan ederken sadece bir kez değerlendirirsiniz i, oysa bu döngü için

for(var i = 1; i <= array.length; i++)

Eğer değerlendirmek .lengthsen artırmak her zaman ieğer kontrol ederken, i <= array.length.

Çoğu durumda bu tür bir optimizasyon hakkında bile endişelenmemelisiniz .


23
array.length için bir değişken tanıtmak ve for döngüsü başlığında kullanmak için değer mi?
ragatskynet

39
@ragatskynet: Bir kıyaslama belirlemediğiniz ve bir noktaya değinmek istemediğiniz sürece hayır.
Jon

29
@ragatskynet Şunlara bağlıdır: .lengthbelirli sayıları değerlendirmek veya yeni bir değişken tanımlamak ve tanımlamak daha hızlı mı olacak ? Çoğu durumda, lengthdeğerlendirmeniz çok pahalı olmadığı sürece bu erken (ve yanlış) optimizasyondur .
alestanis

10
@ Dr.Dredel: Karşılaştırma değil - değerlendirme. 0değerlendirmek daha hızlıdır array.length. Sözde.
Yörüngedeki Hafiflik Yarışları

22
Bahsetmeye değer, Ruby, Python gibi yorumlanmış dillerden bahsediyoruz. Derlenmiş diller, örneğin Java, derleyici düzeyinde, bu farklılıkları .lengthbildirimde bulunup bulunmadığı önemli olmadığı noktaya "düzelten" optimizasyonlara sahiptir for loop.
Haris Krajina

198

Bu adam , birçok tarayıcıda javascript'teki birçok döngüyü karşılaştırdı. Ayrıca bir test paketi vardır, böylece onları kendiniz çalıştırabilirsiniz.

Her durumda (benim okuma bir cevapsız sürece) en hızlı döngü oldu:

var i = arr.length; //or 10
while(i--)
{
  //...
}

Güzel :) Ama "" test için geri "yoktur ... Ama peirix veya searlea tarafından belirtilen döngüler için durumu olarak" while "döngüsü ile" while "döngüsü ile hemen hemen aynı olmalıdır. Ve test edilen en hızlı döngü buydu.
SvenFinke

11
İlginç, ama ön düşüşün daha hızlı olup olmayacağını merak ediyorum. İ'nin ara değerini saklamak zorunda olmadığından.
tvanfosson

Doğru hatırlıyorsam, donanım kursu prof. 0'ın 0 olup olmadığını test etmenin mümkün olan en hızlı "hesaplama" olduğunu söyledi. Süre (i--) test her zaman 0 için bir testtir. Belki de bu yüzden en hızlısıdır?
StampedeXV

3
@tvanfosson Eğer ön düşüşü varsa --io zaman var current = arr[i-1];döngü içinde kullanmak zorunda ya da biri tarafından kapalı olacak ...
DaveAlger

2
İ-- 'den daha hızlı olabileceğini duydum çünkü ikinci durumda işlemcinin azalması ve yeni değere karşı test etmesi gerekiyor (talimatlar arasında veri bağımlılığı var), ilk durumda işlemci ise Mevcut değeri test edin ve bir süre sonra değeri azaltın. Bunun JavaScript veya yalnızca çok düşük düzeyli C kodu için geçerli olup olmadığından emin değilim.
marcus

128

Bu cevapla geniş bir resim vermeye çalışıyorum.

Parantez içindeki şu düşünceler oldu ben sadece son zamanlarda konuyu test ettik kadar inancımı:

[[ C / C ++ gibi düşük seviyeli diller açısından kod, bir değişken sıfır olduğunda (veya sıfır olmadığında) işlemcinin özel bir koşullu atlama komutuna sahip olması için derlenir. Ayrıca, bu kadar optimizasyonu önemsiyorsanız, bunun yerine gidebilirsiniz , çünkü tek bir işlemci komutu anlamına gelir .]]
++ii++++ii++j=i+1, i=j

Gerçekten hızlı döngüler onları açarak yapılabilir:

for(i=800000;i>0;--i)
    do_it(i);

Şundan çok daha yavaş olabilir

for(i=800000;i>0;i-=8)
{
    do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7);
}

ancak bunun nedenleri oldukça karmaşık olabilir (sadece bahsetmek gerekirse, oyunda işlemci komutu önişleme ve önbellek işleme sorunları vardır).

İstediğiniz gibi JavaScript gibi üst düzey diller açısından, kütüphanelere, döngü için yerleşik işlevlere güveniyorsanız işleri optimize edebilirsiniz. En iyi nasıl yapılacağına karar vermelerine izin verin.

Sonuç olarak, JavaScript'te,

array.forEach(function(i) {
    do_it(i);
});

Ayrıca hataya daha az eğilimlidir ve tarayıcıların kodunuzu optimize etme şansı vardır.

[HATIRLATMA: sadece tarayıcılar değil, aynı zamanda kolayca optimize edebileceğiniz bir alanınız var forEach, en yeni en iyi hileyi kullanması için işlevi (tarayıcıya bağlı olarak) yeniden tanımlamanız yeterli ! :) @AMK özel durumlarda array.popveya kullanmaya değer olduğunu söylüyor array.shift. Bunu yaparsanız, perdenin arkasına koyun. En fazla aşırıforEach döngü, döngü algoritmasını seçmek için seçenekler eklemektir .]

Ayrıca, düşük seviyeli diller için de en iyi uygulama, mümkünse karmaşık, ilmekli işlemler için bazı akıllı kütüphane işlevlerini kullanmaktır.

Bu kütüphaneler ayrıca (çok iş parçacıklı) şeyleri arkanıza da koyabilir ve ayrıca uzman programcılar onları güncel tutar.

Biraz daha fazla inceleme yaptım ve C / C ++ 'da, 5e9 = (50.000x100.000) operasyonlar için bile, testin @alestanis'in söylediği gibi bir sabite karşı yapılması durumunda yukarı ve aşağı gitme arasında bir fark olmadığı ortaya çıkıyor. (JsPerf sonuçları bazen tutarsızdır, ancak genel olarak aynı şeyi söylerler: büyük bir fark yaratamazsınız.)
Yani --ioldukça "lüks" bir şey olur. Sadece daha iyi bir programcı gibi görünmenizi sağlar. :)

Öte yandan, bu 5e9 durumda un-unrolling için, 10s gittiğimde 12 saniye 2.5 saniye ve 20s gittiğimde 2.1 saniye düştü. Optimizasyon yoktu ve optimizasyon işleri ölçülemez az zamana indirdi. :) (Kaldırma işlemi yukarıdaki şekilde veya kullanarak yapılabilir i++, ancak bu JavaScript'te bir şey getirmez.)

Sonuçta: tutmak i--/ i++ve ++i/ i++iş görüşmeleri, sopa ki farklar array.forEacholan veya diğer kompleks kütüphane fonksiyonları. ;)


18
Anahtar kelime "olabilir". Açılmamış döngünüz orijinal olandan daha yavaş olabilir. Optimize ederken her zaman ölçün, böylece değişikliklerinizin ne gibi bir etkisi olduğunu tam olarak bilirsiniz.
jalf

1
@jalf true, +1. Farklı açılma uzunlukları (> = 1) verimlilik bakımından farklıdır. Bu nedenle, tarayıcıların farklı mimarilerde çalıştığından bahsetmemek gerekirse, bu işi mümkünse kütüphanelere bırakmak daha uygundur, bu yüzden nasıl yapılacağına karar vermeleri daha iyi olabilir array.each(...). Döngüler düz döngülerle deneyip deneyeceklerini sanmıyorum.
Barney

1
@BarnabasSzabolcs Soru C veya diğer diller için değil, özellikle JavaScript içindir. JS orada olan bir fark, aşağıda benim cevap bakınız. Soru için geçerli olmasa da, +1 iyi cevap!
AMK

1
Ve işte gidiyorsun - +1sana bir Great Answerrozet almak için . Gerçekten harika bir cevap. :)
Rohit Jain

1
APL / A ++ da bir dil değildir. İnsanlar bunları dil özellikleriyle değil, bu dillerin paylaştığı bir şeyle ilgilendiklerini ifade etmek için kullanırlar.
Barney

33

i-- kadar hızlı i++

Aşağıdaki bu kod sizinki kadar hızlıdır, ancak fazladan bir değişken kullanır:

var up = Things.length;
for (var i = 0; i < up; i++) {
    Things[i]
};

Öneri, dizinin boyutunu her seferinde DEĞİL olarak değerlendirmektir. Büyük diziler için performans düşüşü görülebilir.


6
Burada açıkça yanılıyorsunuz. Artık döngü kontrolü için ekstra dahili değişken (i ve üstü) gerekir ve JavaScript motoruna bağlı olarak bu, kodu optimize etme potansiyelini sınırlayabilir. JIT'ler basit döngüleri doğrudan makine opcode'lerine çevirir, ancak döngüler çok fazla değişkene sahipse JIT iyi olarak optimize edemez. Genellikle, JIT'in kullandığı mimari veya cpu kayıtları ile sınırlıdır. Bir kez başlatma ve en temiz çözüm aşağı inme ve bu yüzden her yerde tavsiye edilir.
Pavel P

Ek değişken, ortak bir tercüman / derleyicinin optimize edicisi tarafından ortadan kaldırılacaktır. Mesele '0 ile karşılaştır' - daha fazla açıklama için cevabımı görün.
H.-Dirk Schmitt

1
Döngünün içine 'koymak' daha iyi:for (var i=0, up=Things.length; i<up; i++) {}
thdoan

22

Konuyla ilgilendiğiniz için, JavaScript döngü karşılaştırması hakkında Greg Reimer'ın web günlüğü yayınına bir göz atın, JavaScript'te bir Döngü Kodlamanın En Hızlı Yolu Nedir? :

JavaScript'te döngüleri kodlamanın farklı yolları için bir döngü karşılaştırma testi paketi oluşturdum. Bunlardan birkaçı zaten var, ancak yerel diziler ve HTML koleksiyonları arasındaki farkı kabul eden herhangi bir şey bulamadım.

Ayrıca bir döngüde bir performans testi açarak da yapabilirsiniz https://blogs.oracle.com/greimer/resource/loop-test.html(JavaScript tarayıcıda örneğin NoScript tarafından engellendiyse çalışmaz ).

DÜZENLE:

Milan Adamovsky tarafından oluşturulan daha yeni bir kriter, burada farklı tarayıcılar için çalışma zamanında gerçekleştirilebilir .

Bir For Mac OS X Firefox 17.0 in Testini 10.6 Aşağıdaki döngü var:

var i, result = 0;
for (i = steps - 1; i; i--) {
  result += i;
}

en hızlı olduğu gibi:

var result = 0;
for (var i = steps - 1; i >= 0; i--) {
  result += i;
}

Karşılaştırma örneği.


5
Bu yazı şu anda 4 yaşında. JavaScript motorlarının güncellenme hızı (ha!) Göz önüne alındığında, tavsiyelerin çoğunun eski olması muhtemeldir - makale Chrome'dan bile bahsetmez ve parlak V8 JavaScript motorudur.
Yi Jiang

Evet, bu ayrıntıyı özlüyorum, işaret ettiğiniz için teşekkürler. Olay o zaman döngü için --i veya i ++ arasında çok fazla bir fark yoktu.
dreamcrash

19

Bu --ya da değil ++, karşılaştırma işlemidir. İle --0 ile bir karşılaştırma kullanabilirsiniz, bununla birlikte ++uzunluğu ile karşılaştırmanız gerekir. İşlemcide, normalde sıfır ile karşılaştırmak mümkündür, ancak sonlu bir tamsayı ile karşılaştırmak bir çıkarma gerektirir.

a++ < length

aslında derlendi

a++
test (a-length)

Bu yüzden derlendiğinde işlemcide daha uzun sürer.


15

Kısa cevap

Normal kod için, özellikle JavaScript gibi üst düzey bir dilde , i++ve öğelerinde performans farkı yoktur i--.

Performans kriterleri fordöngüdeki kullanım ve karşılaştırma ifadesidir.

Bu , tüm üst düzey diller için geçerlidir ve çoğunlukla JavaScript kullanımından bağımsızdır. Açıklama, en alt satırda ortaya çıkan birleştirici kodudur.

Detaylı açıklama

Bir döngüde bir performans farkı oluşabilir. Arka plan, montajcı kodu düzeyinde , a'nıncompare with 0 ek bir kayıt gerektirmeyen tek bir deyim olduğunu görebilirsiniz .

Bu karşılaştırma, döngünün her geçişinde verilir ve ölçülebilir bir performans artışı ile sonuçlanabilir.

for(var i = array.length; i--; )

şöyle bir sahte kodla değerlendirilir :

 i=array.length
 :LOOP_START
 decrement i
 if [ i = 0 ] goto :LOOP_END
 ... BODY_CODE
 :LOOP_END

Not bu 0 değişmez ya da başka bir deyişle, sabit bir değerdir.

for(var i = 0 ; i < array.length; i++ )

böyle bir sahte kodla değerlendirilecektir (normal yorumlayıcı optimizasyonu varsayılmaktadır):

 end=array.length
 i=0
 :LOOP_START
 if [ i < end ] goto :LOOP_END
 increment i
 ... BODY_CODE
 :LOOP_END

Not o bir ihtiyacı olan bir değişkendir CPU kayıt. Bu yakarmak olabilir ek sicil takas kodunda ve bir ihtiyacı daha pahalı karşılaştırmak deyimi içinde ifdeyimi.

Sadece 5 sentim

Üst düzey bir dil için, sürdürülebilirliği kolaylaştıran okunabilirlik, küçük bir performans iyileştirmesi olarak daha önemlidir.

Normalde dizi başından sonuna kadar klasik yineleme daha iyidir.

Dizi sonundan başlayarak daha hızlı yineleme , olası istenmeyen ters sırayla sonuçlanır.

Komut dosyası yayınla

Bir yorumda sorulduğu gibi: Azaltma öncesi veya sonrası arasındaki fark --ive i--değerlendirmededir i.

En iyi açıklama denemek ;-) İşte bir Bash örneği.

 % i=10; echo "$((--i)) --> $i"
 9 --> 9
 % i=10; echo "$((i--)) --> $i"
 10 --> 9

1
1+ İyi açıklama. Sadece biraz kapsam dışı bir soru, --ive arasındaki farkı açıklayabilir misiniz i--?
Afshin Mehrabani

14

Aynı öneriyi Sublime Text 2'de gördüm.

Daha önce söylendiği gibi, ana iyileştirme for döngüsünde her yinelemede dizinin uzunluğunu değerlendirmemektedir. Bu, iyi bilinen bir optimizasyon tekniğidir ve dizi HTML belgesinin bir parçası olduğunda JavaScript'te etkilidir ( fortüm liöğeler için bir yapıyor ).

Örneğin,

for (var i = 0; i < document.getElementsByTagName('li').length; i++)

daha yavaş

for (var i = 0, len = document.getElementsByTagName('li').length; i < len; i++)

Ben duruyorum yerden, sorunuzu şeklinde ana bir iyileşme (ekstra bir değişkeni bildirmek olmadığı gerçektir lenbizim örneğimizde)

Ama bana sorarsanız, bütün mesele i++vs i--optimizasyonu değil, her yinelemede dizinin uzunluğunu değerlendirmekle ilgili değildir ( jsperf'de bir kıyaslama testi görebilirsiniz ).


1
Burada hesaplanan kelimeyi istisna etmeliyim . Pavel'in cevabı hakkındaki yorumuma bakın . ECMA özelliği, diziye başvurduğunuzda dizi uzunluğunun hesaplanmadığını belirtir.
kojiro

'Değerlendirme' daha iyi bir seçim olur mu? İlginç gerçek btw, bunu bilmiyordum
BBog

Ek değişken, ortak bir tercüman / derleyicinin optimize edicisi tarafından ortadan kaldırılacaktır. Aynı şey array.length değerlendirmesi için de geçerlidir. Mesele '0 ile karşılaştır' - daha fazla açıklama için cevabımı görün.
H.-Dirk Schmitt

@ H.-DirkSchmitt sizin sağduyu cevap bir yana, uzun JavaScript tarihinin derleyici yaptığı için değil arama zincirinin performans maliyeti optimize uzakta. İlk deneyen AFAIK V8 oldu.
kojiro

@ H.-DirkSchmitt, kojiro'nun dediği gibi, bu iyi bilinen ve köklü bir numara. Modern tarayıcılarda artık geçerli olmasa bile, bu hala kullanılmıyor. Ayrıca, ya uzun bir süre için yeni bir değişken sunarak ya da OP'nin sorusundaki hile ile yapmak, hala en iyi yol, imo. Bu sadece akıllı bir şey ve iyi bir uygulama, derleyicinin JS'de sıklıkla kötü bir şekilde yapılan bir şeyle ilgilenmek için optimize edilmiş
olmasıyla ilgili

13

JavaScript'ten i--daha hızlı olduğunu söylemenin mantıklı olduğunu düşünmüyorum i++.

Her şeyden önce , tamamen JavaScript motoru uygulamasına bağlıdır.

İkincisi , en basit JIT'i kurması ve yerel talimatlara çevrilmesi şartıyla, i++vs i--, tamamen onu çalıştıran CPU'ya bağlı olacaktır. Yani, ARM'lerde (cep telefonları), azalma ve sıfıra kıyasla tek bir komutla yürütüldüğünden 0'a inmek daha hızlıdır.

Muhtemelen, birinin diğerinden daha fazla atık olduğunu düşündün çünkü önerilen yol

for(var i = array.length; i--; )

ancak önerilen yol, biri diğerinden daha hızlı olduğu için değil,

for(var i = 0; i < array.length; i++)

her yinelemede array.lengthdeğerlendirilmek zorundaydı (daha akıllı JavaScript motoru, döngünün dizinin uzunluğunu değiştirmeyeceğini tahmin edebilir). Basit bir ifade gibi görünse de, aslında JavaScript motoru tarafından başlık altında çağrılan bir işlevdir.

Diğer neden, i--"daha hızlı" olarak değerlendirilmesinin nedeninin nedeni, JavaScript motorunun döngüyü kontrol etmek için yalnızca bir dahili değişken ayırması gerektiğidir (değişken var i). Array.length veya başka bir değişkenle karşılaştırdıysanız, döngüyü kontrol etmek için birden fazla dahili değişken olması gerekiyordu ve dahili değişkenlerin sayısı bir JavaScript motorunun sınırlı varlığıdır. Bir döngüde ne kadar az değişken kullanılırsa JIT'in optimizasyon şansı o kadar artar. Bu yüzden i--daha hızlı düşünülebilir ...


3
Muhtemelen nasıl array.lengthdeğerlendirildiği konusunda dikkatli ifadelere değer . Uzunluğu belirttiğinizde hesaplanmaz . (Yalnızca bir dizi dizini oluşturulduğunda veya değiştirildiğinde ayarlanan bir özelliktir ). Ek maliyet olduğunda, JS motoru bu ad için arama zincirini optimize etmediğidir.
kojiro

Ecma spec'in ne dediğinden emin değilim, ancak farklı JavaScript motorlarının bazı içlerini bilmek basit değil getLength(){return m_length; }çünkü bazı temizlik işleri var. Ancak geriye doğru düşünmeye çalışırsanız: uzunluğun gerçekten hesaplanması gereken dizi uygulaması yazmak oldukça dahice olur :)
Pavel P

ECMA Spec gerektirir length özelliği zaten hesaplanabilir söyledi. lengthBir-bir özellik yani-bir-dizi-indeks eklendi veya her değiştiğinde hemen güncellenmelidir.
kojiro

Söylemeye çalıştığım şey, düşünmeye çalışırsanız spesifikasyonu ihlal etmenin oldukça zor olduğudur.
Pavel P

1
x86 bu açıdan ARM gibidir. dec/jnzvs inc eax / cmp eax, edx / jne.
Peter Cordes

13

Diğer cevapların hiçbiri sizin özel sorunuza cevap vermediği için (yarısından fazlası C örnekleri gösteriyor ve alt düzey dilleri tartışıyor, sorunuz JavaScript için) Kendi sorumluluğu yazmaya karar verdim.

İşte böyle:

Basit cevap: i-- genellikle daha hızlıdır, çünkü her çalıştığında 0 ile bir karşılaştırma yapmak zorunda değildir, çeşitli yöntemlerde test sonuçları aşağıdadır:

Test sonuçları: Bu jsPerf tarafından "kanıtlanmış" olduğu gibi arr.pop(), aslında açık arayla en hızlı döngü. Ama odaklanarak --i, i--, i++ve ++iözetlenmiştir sonuçlarında size soru sorulduğunda gibi burada (aşağıdaki kaynaklardan bakın, birden jsPerf en gelmektedir) jsPerf şunlardır:

--ive Chrome'da daha hızlı i--iken Firefox'ta aynıdır i--.

Chrome'da bir temel for döngüsü ( for (var i = 0; i < arr.length; i++)) Firefox'takinden daha hızlıdır i--ve --idaha yavaştır.

Chrome ve Firefox'ta önbelleğe alınan arr.lengthChrome, yaklaşık 170.000 ops / sn önde Chrome ile önemli ölçüde daha hızlıdır.

Önemli bir fark olmadan , çoğu tarayıcıdan ++idaha hızlıdır i++, AFAIK, hiçbir tarayıcıda asla tersi olmaz.

Kısa özet: arr.pop() açık arayla en hızlı döngüdür; özel olarak belirtilen döngüler için, i--en hızlı döngüdür.

Kaynaklar: http://jsperf.com/fastest-array-loops-in-javascript/15 , http://jsperf.com/ipp-vs-ppi-2

Umarım bu soruya cevap verir.


1
Sizin görünüyor popkadarıyla söyleyebilirim - bu döngünün çoğunluğu için 0'a dizi boyutunda aşağı azaltarak çünkü test sadece o kadar hızlı görünüyor. Ancak şeylerin adil olduğundan emin olmak için bu jsperf'i her testte aynı şekilde oluşturmak için tasarladım - ki .shift()birkaç tarayıcımın galibi gibi görünüyor - umduğum
Pebbl

Bahsedilen tek kişi olduğu için ++i
seçildi

12

Dizinizin belleğe yerleştirilmesine ve bu diziye erişirken bellek sayfalarının isabet oranına bağlıdır.

Bazı durumlarda, isabet oranındaki artış nedeniyle dizi üyelerine sütun sırasına erişmek satır sırasından daha hızlıdır.


1
Sadece OP neden farklı siparişlerde aynı matris çaprazlama farklı zaman alabilir ..
sormuştu

1
İşletim Sistemlerinde bellek yönetiminin Disk Belleğe Dayalı olduğu düşünüldüğünde, bir işlem önbelleğe alınmış sayfalarda olmayan bir veriye ihtiyaç duyduğunda, işletim sisteminde bir sayfa hatası oluştuğunu ve hedef sayfayı CPU önbelleğine getirip başka bir sayfa ile değiştirmesi gerektiğini, işlemede hedef sayfanın CPU önbelleğindekinden daha fazla zaman alan ek yüke neden olur. İçindeki her satırın sayfa işletim sistemi boyutundan daha büyük olduğunu ve satır sırasına eriştiğimizi varsayalım ki bu durumda sayfa hata oranı artar ve sonuç, bu diziye sütun sırası erişiminden daha yavaş olur.
Akbar Bayati

Sayfa hataları, önbellek özledikleriyle aynı şey değildir. Yalnızca belleğiniz diske disk belleği takılmışsa sayfa hatası yaparsınız. Çok boyutlu dizilere, bellekte nasıl depolandıklarına ilişkin sırayla erişmek, sayfa hataları nedeniyle değil, önbellek konumu nedeniyle (önbellek satırının tüm baytlarını kullanarak) daha hızlıdır. (çalışma setiniz kullandığınız bilgisayar için çok büyük değilse.)
Peter Cordes

10

En son rahatsız ettiğim zaman 6502 derleme (8 bit, evet!) Yazarken oldu . Büyük kazanç, çoğu aritmetik işlemin (özellikle azalmalar) bir dizi bayrağı güncelledi, bunlardan biri Z'sıfıra ulaştı' göstergesi oldu.

Bu nedenle, döngünün sonunda sadece iki talimat yaptınız: DEC(azalma) ve JNZ(sıfır değilse atlama), karşılaştırmaya gerek yok!


JavaScript söz konusu olduğunda açıkça geçerli değildir (bu tür op kodları olmayan CPU'larda çalıştığı için). Büyük olasılıkla ardındaki gerçek nedeni i--vs i++eski ile size döngünün kapsamında ekstra kontrol değişkenleri tanıtmak kalmamasıdır. Aşağıdaki cevabımı gör ...
Pavel P

1
doğru, gerçekten geçerli değil; ama bu çok yaygın bir C stili ve buna alışmış olanlarımız için daha temiz görünüyor. :-)
Javier

x86 ve ARM bu açıdan 6502 gibidir. x86 kasası dec/jnzyerine inc/cmp/jne. Boş bir loopun daha hızlı çalıştığını görmezsiniz (her ikisi de şube verimini doyurur), ancak geri sayım döngü yükünü biraz azaltır. Mevcut Intel HW ön getiricileri de azalan sırada gelen bellek erişim kalıplarından rahatsız olmuyor. Sanırım daha eski CPU'lar 4 geri akış ve 6 veya 10 ileri akış gibi izleyebilir, IIRC.
Peter Cordes

7

JavaScript (ve tüm diller) sonunda CPU üzerinde çalıştırmak için opcode dönüştürülerek açıklanabilir. CPU'ların sıfıra karşı karşılaştırmak için her zaman tek bir talimatı vardır;

Bir yana, counther zaman >= 0olduğunu garanti edebilirseniz , basitleştirebilirsiniz:

for (var i = count; i--;)
{
  // whatever
}

1
Daha kısa kaynak kodu mutlaka daha hızlı olacağı anlamına gelmez. Ölçtün mü?
Greg Hewgill

Hata! Bunu kaçırdım. Kafasına çivi çak.
Robert

1
0 ile karşılaştırmanın farklı olduğu montaj kaynaklarını görmek istiyorum. Birkaç yıl oldu, ama bir zamanlar bir ton montaj kodlaması yaptım ve hayatım boyunca 0'a karşı eşit derecede hızlı olamayacak şekilde bir karşılaştırma / test yapmanın bir yolunu düşünemiyorum diğer tamsayılar için. Yine de, söyledikleriniz doğru gözüküyor. Neden olduğunu anlayamıyorum sinirli!
Brian Knoblauch

7
@Brian Knoblauch: "dec eax" (x86 kodu) gibi bir komut kullanırsanız, bu talimat otomatik olarak aralarında başka bir karşılaştırma talimatı kullanmadan test edebileceğiniz Z (sıfır) bayrağını otomatik olarak ayarlar.
Greg Hewgill

1
Javascript'i yorumlarken, opcodların darboğaz olacağını düşünmekteyim. Daha az belirteç olması daha olasıdır, yorumlayıcı kaynak kodunu daha hızlı işleyebilir.
Todd Owen

6

Bu, --veya ++işaretine bağlı değildir , ancak döngüde uyguladığınız koşullara bağlıdır.

Örneğin: Değişkenin statik bir değeri varsa döngünüz, bir dizinin uzunluğu veya diğer koşullar gibi her seferinde döngü denetim koşullarından daha hızlıdır.

Ancak bu optimizasyon hakkında endişelenmeyin, çünkü bu sefer etkisi nanosaniye olarak ölçülür.


Birden çok nanosaniye döngü saniye haline gelebilir ... bunun için zamanınız olduğunda optimize etmek asla kötü bir fikir değildir
Buksy

6

for(var i = array.length; i--; )çok daha hızlı değil. Değiştirmeye Ama array.lengthbirlikte super_puper_function(), olabilir önemli ölçüde (her tekrarında denir beri) daha hızlı. Aradaki fark bu.

2014 yılında değiştirecekseniz, optimizasyonu düşünmeniz gerekmez. "Arama ve Değiştirme" ile değiştirecekseniz, optimizasyonu düşünmenize gerek yoktur. Zamanınız yoksa, optimizasyon hakkında düşünmenize gerek yoktur. Ama şimdi bunu düşünmek için zamanın var.

PS: i--daha hızlı değil i++.


6

Kısaca kesmek için: Bunu JavaScript'te yapmanın kesinlikle bir farkı yoktur.

Her şeyden önce, kendiniz test edebilirsiniz:

Herhangi bir JavaScript kitaplığındaki herhangi bir komut dosyasını test etmek ve çalıştırmakla kalmaz, aynı zamanda önceden yazılmış komut dosyalarının tamamına ve farklı platformlarda farklı tarayıcılarda yürütme süresi arasındaki farkları görme yeteneğine de erişebilirsiniz.

Gördüğünüz kadarıyla, herhangi bir ortamdaki performans arasında bir fark yoktur.

Komut dosyanızın performansını artırmak istiyorsanız, yapmaya çalışabileceğiniz şeyler:

  1. var a = array.length;Döngüdeki her seferinde değerini hesaplamamanız için bir ifade alın
  2. Döngü kilidini açma http://en.wikipedia.org/wiki/Loop_unwinding

Ancak, elde edebileceğiniz iyileşmenin o kadar önemsiz olacağını anlamalısınız, çoğunlukla bunu önemsememeniz gerekir.

Kendi fikrim neden böyle bir yanlış anlama (Dec vs Inc) ortaya çıktı

Uzun zaman önce DSZ (Azaltma ve Atlama Sıfıra) gibi ortak bir makine talimatı vardı. Montaj dilinde programlanmış kişiler, bir kayıt kaydetmek için döngüler uygulamak için bu komutu kullandı. Şimdi bu eski gerçekler kullanılmıyor ve bu sözde gelişmeyi kullanarak herhangi bir dilde herhangi bir performans artışı elde edemeyeceğinizden eminim.

Sanırım bu tür bilginin zamanımızda yayılabilmesinin tek yolu, başkasının kişi kodunu okumanızdır. Böyle bir yapıyı görün ve neden uygulandığını sorun ve burada cevap: "sıfıra kıyasla performansı artırır". Meslektaşınla ilgili daha fazla bilgiden şaşkına döndün ve bunu daha akıllı olmak için kullanmayı düşündün :-)


İlginç, ancak win7'de firefox 16.0.2 altında çalışan testleriniz için, azalma döngüsü% 29 daha yavaştı ... EDIT: Bunu dikkate almayın. Tekrarlanan testler sonuçsuz kaldı, sonraki çalışmalarda test sonuçlarımda şaşırtıcı miktarda gürültü var. Neden olduğundan emin değilim.

Evet, diğer her şeyi kapatarak ve sadece testleri yaparak hesaplamaya çalıştım. Hala sakat sonuçlar var. Çok ilginç.

Sanırım sıfıra gitmenin neden JavaScript'te daha iyi olduğu düşünülüyor. Çünkü bu şekilde sadece bir değişken döngü yürütmeyi kontrol eder, örneğin bu şekilde optimizer / JITer iyileştirme için daha fazla alana sahiptir. array.lengthJS sanal makinesi, dizinin döngü gövdesi tarafından değiştirilip değiştirilmediğini anlamaya yetecek kadar akıllı olması nedeniyle, kullanmak her zaman performans cezasına neden olmaz. Cevabımı aşağıda görebilirsiniz.
Pavel P

1
nitpicking: bu eski gerçek (montaj dili optimizasyonları) eski değil , sadece gizlidir. İçinde olduğu gibi gerçekten yapmadığınız sürece bilmenize gerek yok. :-)
Javier

6

Ben jsbench üzerinde bir karşılaştırma yaptım .

Alestani'nin işaret ettiği gibi, yükselen döngülerde zaman alan bir şey, her bir yineleme için dizinizin boyutunu değerlendirmektir. Bu döngüde:

for ( var i = 1; i <= array.length; i++ )

.lengthher artırdığınızda değerlendirirsiniz i. Bu birinde:

for ( var i = 1, l = array.length; i <= l; i++ )

.lengthbeyan ettiğinizde sadece bir kez değerlendirirsiniz i. Bu birinde:

for ( var i = array.length; i--; )

karşılaştırma örtüktür, azalmadan hemen önce gerçekleşir ive kod çok okunabilir. Ancak, müthiş bir fark yaratabilecek olan şey, döngü içine koyduğunuz şeydir.

İşlev çağrısı ile döngü (başka bir yerde tanımlanmıştır):

for (i = values.length; i-- ;) {
  add( values[i] );
}

Satır içi kod ile döngü:

var sum = 0;
for ( i = values.length; i-- ;) {
  sum += values[i];
}

Kodunuzu, bir işlevi çağırmak yerine, okunabilirlikten ödün vermeden satır içine alabiliyorsanız, daha hızlı bir büyüklük sırasına sahip olabilirsiniz!


Not : tarayıcı basit işlevleri satır içinde iyileştirirken , kodunuzun ne kadar karmaşık olduğuna bağlıdır. Optimize etmeden önce profil yapın, çünkü

  1. Darboğaz başka bir yerde olabilir (ajax, reflow, ...)
  2. Daha iyi bir algoritma seçebilirsiniz
  3. Daha iyi bir veri yapısı seçebilirsiniz

Ama hatırla:

Kod, insanların okuması ve yalnızca makinelerin yürütmesi için yazılır.


Bu cevap ve karşılaştırmalı değerlendirme için +1. ForEach testlerini ekledim ve karşılaştırmayı tarayıcıda ve Düğümde çalıştırılabilen bağımsız bir dosyaya yeniden çalıştım. jsfiddle.net/hta69may/2 . Düğüm için "Ters döngü, örtük karşılaştırma, satır içi kod" en hızlısıdır. Ancak FF 50'deki testler ilginç sonuçlar gösterdi: sadece zamanlamalar neredeyse 10 kat daha az değildi (!), Ancak her iki "forEach" testi de "ters döngü" kadar hızlıydı. Belki Düğüm adamları V8 yerine Mozilla'nın JS motorunu kullanmalıdır? :)
Fr0sT

4

Bunu şimdi yapma şekliniz daha hızlı değil (belirsiz bir döngü olmasının dışında, sanırım yapmak istediniz) i--.

Daha hızlı yapmak istiyorsanız:

for (i = 10; i--;) {
    //super fast loop
}

Tabii ki böyle küçük bir döngüde fark etmezsiniz. Daha hızlı olmasının nedeni, "doğru" olup olmadığını kontrol ederken i değerini azaltmanızdır (0'a ulaştığında "yanlış" olarak değerlendirilir)


1
Noktalı virgül eksik mi? (i = 10; i--;)
searlea

Evet evet, hatayı düzelttim. Ve eğer seçici olacaksak, ben senin arkasından yarım kolonunu unuttuğunu göstereceğim. Heh.
djdd87

Neden daha hızlı? Daha kısa kaynak, daha hızlı olacağı anlamına gelmez. Ölçtün mü?
Greg Hewgill

4
Evet, ölçtüm ve daha kısa kaynağın daha hızlı hale getirdiğini söylemiyorum, ancak daha az işlem daha hızlı hale getiriyor.
peirix

4

Bazen kodumuzu yazma biçimimizde çok küçük değişiklikler yapmak, kodumuzun gerçekte ne kadar hızlı çalıştığında büyük bir fark yaratabilir. Küçük bir kod değişikliğinin yürütme sürelerinde büyük bir fark yaratabileceği bir alan, bir diziyi işleyen bir for döngüsüne sahip olduğumuz yerdir. Dizinin web sayfasındaki öğeler (radyo düğmeleri gibi) olduğu yerlerde, değişiklik en büyük etkiye sahiptir, ancak dizinin Javascript kodunun içinde olduğu yerlerde bile bu değişikliği uygulamaya değer.

Bunun gibi bir dizi lis işlemek için bir for döngüsü kodlamanın geleneksel yolu:

for (var i = 0; i < myArray.length; i++) {...

Buradaki sorun, myArray.length kullanarak dizinin uzunluğunun değerlendirilmesinin zaman alması ve döngüyü kodlama şeklimizin, bu değerlendirmenin döngü çevresinde her seferinde yapılması gerektiği anlamına gelir. Dizi 1000 öğe içeriyorsa, dizinin uzunluğu 1001 kez değerlendirilir. Radyo düğmelerine bakıyorduk ve myForm.myButtons.length'e sahip olsaydık, uzunluğun her döngüde değerlendirilmesinden önce belirtilen formdaki uygun düğme grubunun bulunması gerektiğinden değerlendirmek daha da uzun sürer.

Açıkçası, diziyi işlerken dizinin uzunluğunun değişmesini beklemiyoruz, böylece uzunluğun tüm bu yeniden hesaplamaları işlem süresine gereksiz yere ekleniyor. (Tabii ki döngü içinde dizi girişleri ekleyen veya silen kodunuz varsa, dizi boyutu yinelemeler arasında değişebilir ve bu nedenle test eden kodu değiştiremeyiz)

Boyutun sabit olduğu bir döngü için bunu düzeltmek için yapabileceğimiz, döngünün başlangıcında uzunluğu bir kez değerlendirmek ve bir değişkene kaydetmek. Daha sonra, döngüyü ne zaman sonlandıracağına karar vermek için değişkeni test edebiliriz. Bu, özellikle dizi yalnızca birkaç girişten fazlasını içerdiğinde veya web sayfasının bir parçası olduğunda, her seferinde dizi uzunluğunu değerlendirmekten çok daha hızlıdır.

Bunu yapmak için kod:

for (var i = 0, var j = myArray.length; i < j; i++) {...

Şimdi dizinin boyutunu yalnızca bir kez değerlendiriyoruz ve döngü sayacımızı döngü etrafında her seferinde bu değeri tutan değişkenle test ediyoruz. Bu ekstra değişkene dizinin boyutunu değerlendirmekten çok daha hızlı erişilebilir ve böylece kodumuz eskisinden çok daha hızlı çalışacaktır. Senaryomuzda sadece bir tane ekstra değişken var.

Genellikle, dizideki tüm girdiler işlendiği sürece diziyi hangi sırada işlediğimiz önemli değildir. Bu durumda, az önce eklediğimiz ekstra değişkeni ortadan kaldırarak ve diziyi ters sırada işleyerek kodumuzu biraz daha hızlı hale getirebiliriz.

Dizimizi mümkün olan en verimli şekilde işleyen son kod:

for (var i = myArray.length-1; i > -1; i--) {...

Bu kod hala dizinin boyutunu başlangıçta yalnızca bir kez değerlendirir, ancak döngü sayacını bir değişkenle karşılaştırmak yerine onu bir sabitle karşılaştırırız. Bir sabit, bir değişkene erişmek için daha da etkili olduğundan ve kodun üçüncü sürümümüzden daha az bir atama ifademiz olduğundan, şimdi ikinci sürümden biraz daha verimli ve birinciden çok daha verimli.


4

++vs.'nin --önemi yoktur, çünkü JavaScript yorumlanmış bir dildir, derlenmiş bir dil değildir. Her talimat birden fazla makine diline çevrilir ve kanlı ayrıntılarla ilgilenmemelisiniz.

Montaj talimatlarını verimli bir şekilde kullanmak için --(veya ++) kullanmayı konuşan kişiler yanlıştır. Bu komut tamsayı aritmetiği için geçerlidir ve JavaScript'te tamsayı yoktur, sadece sayılar vardır .

Okunabilir kod yazmalısınız.


3

Çoğu durumda, bunun aslında işlemcilerin sıfırı diğer karşılaştırmalardan daha hızlı karşılaştırabilmeleri ile ilgisi yoktur.

Bunun nedeni, sadece birkaç Javascript motorunun (JIT listesindeki motorlar ) aslında makine dil kodu oluşturmasıdır.

Çoğu Javascript motoru, daha sonra yorumladıkları kaynak kodunun dahili bir temsilini oluşturur (bunun nasıl bir şey olduğu hakkında bir fikir edinmek için , Firefox'un SpiderMonkey'inde bu sayfanın alt kısmına bakın ). Genellikle bir kod parçası hemen hemen aynı şeyi yapar ancak daha basit bir dahili temsile yol açarsa, daha hızlı çalışır.

Bir değişkenden bir değişken ekleme / çıkarma veya bir değişkeni bir şeyle karşılaştırma gibi basit görevlerle, yorumlayıcının bir dahili "talimattan" diğerine geçme yükünün oldukça yüksek olduğunu, bu nedenle daha az "talimatların" dahili olarak JS motoru tarafından kullanılırsa, o kadar iyidir.


3

Peki, JavaScript hakkında bilmiyorum, gerçekten sadece dizi yeniden değerlendirme meselesi olmalı ve belki ilişkilendirilebilir dizilerle ilgili bir şey olmalı (sadece azalırsanız, yeni girişlerin tahsis edilmesi muhtemel değildir - eğer dizi yoğun, yani birisi bunun için optimize edebilir).

Düşük seviyeli montajda, DJNZ (sıfır değilse azaltma ve atlama) adı verilen bir döngü talimatı vardır. Bu nedenle, eksiltme ve atlama tek bir komutta, bu da INC ve JL / JB'den daha hızlı bir şekilde daha hızlı hale geliyor (arttırma, eğer daha düşükse atlama / atlamadan daha düşükse). Ayrıca, sıfıra karşı karşılaştırmak başka bir sayıya göre karşılaştırmaktan daha kolaydır. Ancak tüm bunlar gerçekten marjinal ve aynı zamanda hedef mimariye de bağlı (örneğin akıllı telefonda Arm üzerinde fark yaratabilir).

Bu düşük seviyedeki farklılıkların yorumlanmış diller üzerinde çok büyük bir etkisi olmasını beklemezdim, yanıtlar arasında DJNZ'yi görmedim, bu yüzden ilginç bir düşünceyi paylaşacağımı düşündüm.


Kayıt için, DJNZ8051 (z80) ISA'daki bir talimattır. x86 dec/jnzyerine var inc/cmp/jneve görünüşe göre kol benzer bir şey var. Bu Javascript farkının nedeni olmadığından eminim; döngü koşulunu değerlendirmek için daha fazlasına sahip olmak.
Peter Cordes

3

Bu kullanılan tek bir sonuç, indirildiği bir değer yoktur, çünkü (C ++) dibromtriakontan hızlı olduğu söylenebilir. i-- azaltılmış değeri i'ye geri saklamalı ve sonuç olarak orijinal değeri korumalıdır (j = i--;). Çoğu derleyicide bu, bir kayıt defteri değişkeni olarak saklanmak yerine başka bir değişkenin belleğe yazılmasına neden olabilecek biri yerine iki kayıt kullandı.

Bu günlerde hiçbir fark yaratmadığını söyleyenlere katılıyorum.


3

Çok basit bir deyişle

"i-- ve i ++. Aslında ikisi de aynı zamanı alıyor".

ancak bu durumda artımlı işlem yaptığınızda .. işlemci, değişken 1 olduğunda her zaman .length değerini değerlendirir ve azalma durumunda .. özellikle bu durumda, 0 elde edene kadar .length değerini yalnızca bir kez değerlendirir.


3

Birincisi, i++ve i--tam olarak JavaScript dahil olmak üzere herhangi bir programlama dili, aynı zaman alabilir.

Aşağıdaki kod çok farklı zaman alır.

Hızlı:

for (var i = 0, len = Things.length - 1; i <= len; i++) { Things[i] };

Yavaş:

for (var i = 0; i <= Things.length - 1; i++) { Things[i] };

Bu nedenle, aşağıdaki kod da farklı zaman alır.

Hızlı:

for (var i = Things.length - 1; i >= 0; i--) { Things[i] };

Yavaş:

for (var i = 0; i <= Things.length - 1; i++) { Things[i] };

PS Slow , derleyicinin optimizasyonu nedeniyle yalnızca birkaç dilde (JavaScript motorları) yavaştır. En iyi yol yerine '<' yerine '<=' (veya '=') ve '----' yerine 'i--' kullanmaktır .


3

İ-- veya i ++ tarafından çok fazla zaman harcanmaz. CPU mimarisinin derinliklerine giderseniz , işlem 2'nin tamamlayıcısını yapacağından ++daha hızlıdır , ancak donanımın içinde olur, böylece bu onu hızlı hale getirir ve bu işlemler arasında önemli bir fark yoktur . CPU'da en az tüketilen zaman. ----++--

Döngü böyle çalışır:

  • Değişkeni başlangıçta bir kez başlatın.
  • Döngünün ikinci işlenen içinde kısıtlamayı edin, <, >, <=, vb
  • Sonra döngüyü uygulayın.
  • Döngüyü artırın ve döngü tekrar bu işlemleri tekrar atın.

Yani,

for (var i = Things.length - 1; i >= 0; i--) {
    Things[i]
}; 

dizi uzunluğunu başlangıçta yalnızca bir kez hesaplar ve bu çok zaman değildir, ancak

for(var i = array.length; i--; ) 

her döngüdeki uzunluğu hesaplar, böylece çok zaman harcar.


var i = Things.length - 1; i >= 0; i--uzunluğu da 1 kez hesaplar.
Dmitry

1
" --Operasyon 2'nin tamamlayıcısını yapacak " ne anlama geldiğinden emin değilim , ama bunun bir şeyi reddedeceği anlamına geldiğini varsayıyorum. Hayır, hiçbir mimaride hiçbir şeyi olumsuz etkilemez. 1 çıkarmak, 1 eklemek kadar basittir, sadece taşımak yerine ödünç alan bir devre yaparsınız.
Olathe

1

Bu tür bir soruyu cevaplamanın en iyi yolu aslında denemektir. Bir milyon yineleme veya her neyse sayılan bir döngü oluşturun ve bunu her iki şekilde yapın. Her iki döngüyü de zamanlayın ve sonuçları karşılaştırın.

Yanıt muhtemelen kullandığınız tarayıcıya bağlı olacaktır. Bazılarının sonuçları diğerlerinden farklı olacaktır.


4
Bu hala neden daha hızlı olduğu sorusuna cevap vermezdi . Neden bu şekilde olduğunu bilmeden bir kıyaslama yaptı ...
peirix

3
Bu doğru. Ancak, her bir Javascript motorunun her tarayıcıda tam olarak uygulanmasını bilmeden, "neden" kısmına cevap vermek neredeyse imkansızdır. Buradaki cevapların birçoğu "postdecrement yerine predecrement kullan" (bir C ++ optimizasyon hilesi) ve yerel kod derlenmiş dillerde geçerli olabilecek "sıfıra karşı karşılaştır" gibi anekdotsal önerileri ortaya koyuyor, ancak Javascript, İŞLEMCİ.
Greg Hewgill

4
-1 En iyi yaklaşımın bunu denemek olduğuna tamamen katılmıyorum. Birkaç örnek, kolektif bilginin yerini almaz ve bunun gibi forumların hepsi budur.
Christophe

1

Bayıldım, bir sürü not var ama cevap yok: D

Sadece sıfıra karşı bir karşılaştırma koymak her zaman en hızlı karşılaştırmadır

Yani (a == 0), True döndürmede aslında (a == 5) daha hızlıdır

Küçük ve önemsizdir ve bir koleksiyondaki 100 milyon sıra ile ölçülebilir.

yani bir döngü yukarı nerede i <= array.length ve i artırma

aşağı döngüde nerede i> = 0 olduğunu söyleyebilir ve onun yerine i azalıyor olabilirsiniz.

Karşılaştırma daha hızlıdır. Döngünün 'yönü' değil.


Javascript motorlarının hepsi farklı olduğundan ve cevap tam olarak hangi tarayıcıyı ölçtüğünüze bağlı olduğundan, sorunun belirtildiği gibi bir cevap yoktur.
Greg Hewgill

Hayır, temelde kabul edilen sıfıra karşı karşılaştırmalar en hızlısıdır. İfadeleriniz doğru olsa da, sıfıra karşı karşılaştırmanın altın kuralı mutlaktır.
Robert

4
Bu sadece derleyici kesinlikle garanti edilmeyen bir optimizasyon yapmayı seçerse doğrudur . Derleyici, (a == 0) ve (a == 5) için sabitin değeri dışında tam olarak aynı kodu üretebilir. Karşılaştırmanın her iki tarafı da değişkense (CPU açısından) CPU, 0 ile diğer değerlerden daha hızlı karşılaştırmaz. Genellikle yalnızca yerel kod derleyicileri bu düzeyde optimize etme şansına sahiptir.
Greg Hewgill

1

BAŞKA BİR BAŞLIKTAN KAÇININIZA YARDIMCI OLUN!

Bu sayfadaki en popüler cevap Firefox 14 için çalışmıyor ve jsLinter'ı geçmiyor. "while" döngülerinin ödev değil, karşılaştırma operatörü olması gerekir. Krom, safari ve hatta ie üzerinde çalışır. Ancak firefox'ta ölüyor.

BU BOZUK!

var i = arr.length; //or 10
while(i--)
{
  //...
}

BU ÇALIŞACAK! (firefox üzerinde çalışır, jsLinter'i geçer)

var i = arr.length; //or 10
while(i>-1)
{
  //...
  i = i - 1;
}

2
Firefox 14'te denedim ve iyi çalıştı. Çok while (i--)sayıda tarayıcıda çalışan ve çalışan üretim kitaplıklarından örnekler gördüm . Testinizle ilgili garip bir şey olabilir mi? Firefox 14'ün beta sürümünü mü kullanıyordunuz?
Matt Browne

1

Bu sadece bir tahmindir, ancak belki de işlemcinin bir şeyi başka bir değerle (i <Things.length) yerine 0 (i> = 0) ile karşılaştırması daha kolaydır.


3
+1 Başkaları oy kullanmadı. Her ne kadar .length'in değerlendirilmesi, gerçek artış / azalmadan çok daha fazla bir sorun olsa da, döngü sonu kontrolü önemli olabilir. C derleyicim döngüler hakkında bazı uyarılar veriyor: "açıklama # 1544-D: (ULP 13.1) Tespit edilen döngü sayımı. Sıfırları tespit etmek daha kolay olduğu için döngülerin geri sayılmasını önerin"
harper
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.