Hangisi daha hızlı: (1) veya iken (2)?


587

Bu üst düzey bir yönetici tarafından sorulan bir röportaj sorusuydu.

Hangisi daha hızlı?

while(1) {
    // Some code
}

veya

while(2) {
    //Some code
}

I sentezleme içi gibi, her ikisi de aynı uygulama hızına sahip söz konusu whilenihayet değerlendirmelidir trueveya false. Bu durumda, hem değerlendirme yapar hem de truekoşul içinde ekstra koşullu talimat yoktur while. Yani, her ikisi de aynı hızda olacak ve ben (1) 'i tercih ederim.

Ancak görüşmeci güvenle dedi: "Temel bilgilerinizi kontrol edin. while(1)Daha hızlıdır while(2)." (Güvenimi test etmiyordu)

Bu doğru mu?

Ayrıca bkz: "için (;;)", (TRUE) "dan" daha hızlı mı? Değilse, insanlar neden kullanıyor?


202
Yarı iyi bir derleyici, her iki formu da hiçbir şeye optimize etmeyecektir.

64
Optimize edilmiş yapıda her zaman (n), n! = 0 veya for (;;) başlangıçta etiketli, sonunda etiketli Meclis sonsuz döngüsüne çevrilecektir. Tam olarak aynı kod, aynı performans.
Alex F

60
Şaşırtıcı olmayan bir şekilde, stok optimizasyonu her iki snippet 0x100000f90: jmp 0x100000f90için de getiriyor (adres açıkça değişiyor) . Görüşmeci muhtemelen bir kayıt testine karşı basit bir işaretli atlamaya karşı korunmuştur. Hem soru hem de varsayımları topal.
WhozCraig

50
Görüşmeci tarafından bu soru dilbert.com/strips/comic/1995-11-17 ile aynı himayeye girer - ifadelerindeki aptallık bölümü ne olursa olsun söylediklerine gerçekten inanan biriyle tanışacaksınız. Sadece aşağıdakilerden birini seçin: derin bir nefes, küfür, gülmek, ağlamak, yukarıdakilerin bir kombinasyonu :)
GMasucci

3
@Mike W: bir derleyicinin ne yapması gerektiğini merak edebilir: bir Durt deyimine çevirebilir veya döngü sonsuz süreden sonra çıkıp sonsuz gecikmeyi optimize edebilir mi?
Yves Daoust

Yanıtlar:


681

Her iki döngü de sonsuzdur, ancak hangisinin yineleme başına daha fazla talimat / kaynak aldığını görebiliriz.

Gcc'yi kullanarak, aşağıdaki iki programı çeşitli optimizasyon düzeylerinde birleştirmek için derledim:

int main(void) {
    while(1) {}
    return 0;
}


int main(void) {
    while(2) {}
    return 0;
}

Hiçbir optimizasyon ( -O0) yapılmasa bile , oluşturulan montaj her iki program için de aynıydı . Bu nedenle, iki döngü arasında hız farkı yoktur.

Başvuru için, burada oluşturulan derleme ( gcc main.c -S -masm=intelbir optimizasyon bayrağıyla kullanarak ):

İle -O0:

    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    push    rbp
    .seh_pushreg    rbp
    mov rbp, rsp
    .seh_setframe   rbp, 0
    sub rsp, 32
    .seh_stackalloc 32
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

İle -O1:

    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

İle -O2ve -O3(aynı çıkış):

    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .section    .text.startup,"x"
    .p2align 4,,15
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Aslında, döngü için oluşturulan montaj her optimizasyon seviyesi için aynıdır:

 .L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Önemli bitler:

.L2:
    jmp .L2

Montajı çok iyi okuyamıyorum, ama bu açıkça koşulsuz bir döngü. jmpTalimat koşulsuz program geri sıfırlar .L2bile doğru karşı bir değeri karşılaştırarak olmadan etiket ve program nasılsa sona kadar tabii hemen bu nedenle yeniden yapar. Bu doğrudan C / C ++ koduna karşılık gelir:

L2:
    goto L2;

Düzenle:

İlginçtir ki, hiçbir optimizasyon olmasa bile , aşağıdaki döngülerin hepsi jmpmontajda aynı çıktıyı (koşulsuz ) üretti :

while(42) {}

while(1==1) {}

while(2==2) {}

while(4<7) {}

while(3==3 && 4==4) {}

while(8-9 < 0) {}

while(4.3 * 3e4 >= 2 << 6) {}

while(-0.1 + 02) {}

Ve hayretlerime bile:

#include<math.h>

while(sqrt(7)) {}

while(hypot(3,4)) {}

Kullanıcı tanımlı işlevlerle işler biraz daha ilginçleşir:

int x(void) {
    return 1;
}

while(x()) {}


#include<math.h>

double x(void) {
    return sqrt(7);
}

while(x()) {}

At -O0, bu iki örnek aslında xher yineleme için bir karşılaştırma çağırır ve gerçekleştirir.

İlk örnek (1 döndürme):

.L4:
    call    x
    testl   %eax, %eax
    jne .L4
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

İkinci örnek (geri dönüyor sqrt(7)):

.L4:
    call    x
    xorpd   %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    jp  .L4
    xorpd   %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    jne .L4
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Bununla birlikte, -O1her ikisinde de ve her ikisi de önceki örneklerle aynı montajı üretir ( jmpönceki etikete koşulsuz bir geri dönüş).

TL; DR

GCC altında, farklı döngüler özdeş montaj için derlenir. Derleyici sabit değerleri değerlendirir ve gerçek bir karşılaştırma yapmakla uğraşmaz.

Hikayenin ahlakı:

  • C ++ kaynak kodu ve CPU talimatları arasında bir çeviri katmanı vardır ve bu katmanın performans için önemli etkileri vardır.
  • Bu nedenle, performans yalnızca kaynak koduna bakarak değerlendirilemez.
  • Derleyici bu tür önemsiz durumları optimize edecek kadar akıllı olmalıdır . Programcılar olmamalıdır vakaların büyük çoğunluğunda onlar hakkında onların zaman düşünme israf.

196
Belki görüşmeci gcc kullanmıyordu
MM

106
@Matt McNabb Bu iyi bir nokta, ancak görüşmeci derleyiciye özgü optimizasyonlara güveniyorsa, sorularında bu konuda çok açık olmaları gerekir ve "doğru bir şey" cevabını doğru olarak kabul etmeleri gerekir. bazı (en çok?) derleyiciler.
Jonathan Hartley

109
Herhangi bir şüpheyi ortadan kaldırmak için bunu clang 3.4.2'de test ettim ve her iki döngü de her -Oseviyede aynı montajı üretti .
Martin Tournoij

16
Döngülerin koşullu bölümüne yerleştirdiğiniz her şey derleme zamanı sabitleri olduğu için bunu hiç şaşırtıcı bulmuyorum. Bu nedenle, bir derleyicinin döngülerin her zaman doğru veya yanlış olacağını ve sırasıyla basitçe jmpbaşlangıca geri döndüğünü veya döngüyü tamamen kaldıracağını düşünürüm.
sherrellbc

10
@hippietrail Döngünün içeriğinin (ya da eksikliğinin) muhtemelen bu optimizasyonları nasıl etkileyebileceğini görmüyorum (herhangi bir breakifadenin olasılığı hariç ), ama yine de test ettim ve döngüdeki kodla bile atlama mutlak ve her ikisi için de koşulsuz while(1)ve while(2). Gerçekten endişeleniyorsanız diğerlerini kendiniz test etmekten çekinmeyin.
ApproachingDarknessFish

282

Evet, while(1)çok daha hızlı daha while(2), bir insan okumak için! while(1)Bilmediğiniz bir kod tabanında görürsem , yazarın neyi amaçladığını hemen bilirim ve göz kürelerim bir sonraki satıra devam edebilir.

Eğer görürsem while(2), muhtemelen izlerimi durduracağım ve yazarın neden yazmadığını anlamaya çalışacağım while(1). Yazarın parmağı klavyede kaydı mı? Bu kod tabanının koruyucular while(n)döngülerin farklı görünmesini sağlamak için belirsiz bir yorumlama mekanizması olarak mı kullanılıyor? Bazı kırık statik analiz aracında sahte bir uyarı için kaba bir çözüm mü? Yoksa bu oluşturulan kodu okuduğum bir ipucu mu? Kötü bir şekilde tavsiye edilen bul ve değiştir hepsini ya da kötü bir birleşme ya da kozmik bir ışından kaynaklanan bir hata mıdır? Belki de bu kod satırının çok farklı bir şey yapması gerekiyordu. Belki de okuması gerekiyordu while(w)ya while(x2). Dosya geçmişinde yazarı bulsam iyi olur ve onlara bir "WTF" e-postası gönderirim ... ve şimdi zihinsel bağlamımı kırdım.while(2)while(1) saniyenin bir kısmını alır!

Abartıyorum, ama sadece biraz. Kod okunabilirliği gerçekten önemlidir. Ve bu bir röportajda bahsetmeye değer!


Düşüncelerim tam olarak ve tam olarak neden (1) daha hızlı lol iken Ben sadece bir yöneticinin kodlama hakkında bilmediğini bildiğine ikna etmeye çalışan eski bir durum olduğunu düşünmeme rağmen, herkes gördü, herkes olmak istiyor jedi.
ekerner

8
Kesinlikle, bu hiç abartı yok. Kesinlikle svn-annotate veya git blame(veya her ne olursa olsun) burada kullanılacaktır ve genel olarak bir dosya suçlama geçmişi yüklemek dakikalar alır. Sonra nihayet karar "ah anlıyorum, yazar lise taze zaman bu satır yazdı", sadece 10 dakika kaybetti ...
v.oddou

11
Oy verdim çünkü sözleşmelerden bıktım. Geliştirici, sevdiği bir sayı yazmak için bu cılız bir fırsata sahip, daha sonra sıkıcı biri neden olmadığından emin oluyor 1.
Utkan Gezer

1
Retorik nedeniyle reddedildi. While (1) okuma işlemi, (2) ile aynı hızdadır.
hdante

4
Bir dakika önce bu cevapta anlatılanla aynı zihinsel süreçten geçtim while(2)ve kodda gördüğümde ("Bu kod tabanının koruyucular, (n) döngülerin farklı görünmesini sağlamak için belirsiz bir yorumlama mekanizması olarak kullanılırken?" ). Yani hayır, abartmıyorsun!
Hisham HM

151

Belirli bir derleyici tarafından belirli bir seçenek kümesi ile belirli bir hedef için oluşturulan kodu gösteren mevcut yanıtlar soruyu tam olarak yanıtlamaz - bu belirli bağlamda soru sorulmadıkça ("x86_64 için gcc 4.7.2 kullanarak daha hızlıdır varsayılan seçeneklerle? "

Dil tanımına gelince, soyut makinede while (1) tamsayı sabitini 1ve while (2)tamsayı sabitini değerlendirir 2; her iki durumda da sonuç sıfıra eşitlik için karşılaştırılır. Dil standardı, iki yapının göreceli performansı hakkında kesinlikle hiçbir şey söylemez.

Son derece saf bir derleyicinin, en azından optimizasyon talep etmeden derlendiğinde, iki form için farklı makine kodu üretebileceğini hayal edebiliyorum.

Öte yandan, C derleyicileri, sabit bir ifade gerektiren bağlamlarda göründüklerinde, derleme zamanında bazı sabit ifadeleri mutlaka değerlendirmelidir . Örneğin, bu:

int n = 4;
switch (n) {
    case 2+2: break;
    case 4:   break;
}

bir teşhis gerektirir; tembel bir derleyicinin değerlendirmesini 2+2yürütme süresine kadar erteleme seçeneği yoktur . Bir derleyicinin derleme zamanında sabit ifadeleri değerlendirme yeteneğine sahip olması gerektiğinden, gerekli olmadığında bile bu özellikten yararlanmaması için iyi bir neden yoktur.

C standardı ( N1570 6.8.5p4) diyor ki

Bir yineleme ifadesi, döngü ifadesi adı verilen bir ifadenin , kontrol ifadesi 0'a eşit olana kadar tekrar tekrar yürütülmesine neden olur .

Dolayısıyla, ilgili sabit ifadeler 1 == 0ve 2 == 0her ikisi de intdeğeri değerlendirir 0. (Bu karşılaştırma, whiledöngünün anlambiliminde örtüktür; gerçek C ifadeleri olarak mevcut değildir.)

Bir perversely naif derleyici olabilir iki yapı için farklı bir kod üretir. Örneğin, birincisi için koşulsuz bir sonsuz döngü oluşturabilir ( 1özel bir durum gibi davranır) ve ikincisi için açık bir çalışma zamanı karşılaştırması oluşturabilir 2 != 0. Ama bu şekilde davranacak bir C derleyicisiyle hiç karşılaşmadım ve böyle bir derleyicinin varlığından ciddi olarak şüpheliyim.

Çoğu derleyici (tüm üretim kalitesi derleyicilerinin söylemeye hazırım) ek optimizasyon isteme seçenekleri var. Böyle bir seçenek altında, herhangi bir derleyicinin iki form için farklı kod üretmesi daha az olasıdır.

Derleyiciniz iki yapı için farklı kod üretirse, öncelikle farklı kod dizilerinin gerçekten farklı performansa sahip olup olmadığını kontrol edin. Varsa, bir optimizasyon seçeneğiyle tekrar derlemeyi deneyin (varsa). Hala farklıysa, derleyici satıcısına bir hata raporu gönderin. C standardına uymama anlamında (mutlaka) bir hata değildir, ancak neredeyse kesinlikle düzeltilmesi gereken bir sorundur.

Alt satır: while (1)ve while(2) neredeyse kesinlikle aynı performansa sahip. Tam olarak aynı semantiğe sahiptirler ve herhangi bir derleyicinin aynı kodu üretmemesinin iyi bir nedeni yoktur.

Ve bir derleyicinin için while(1)olduğundan daha hızlı kod üretmesi tamamen yasal olsa da, bir derleyicinin aynı programdaki başka bir oluşumdan daha while(2)hızlı kod üretmesi de aynı derecede yasaldır .while(1)while(1)

(Sorduğunuz soruda başka bir soru daha var: Yanlış bir teknik noktada ısrar eden bir görüşmeci ile nasıl başa çıkıyorsunuz. Bu muhtemelen İşyeri sitesi için iyi bir soru olacaktır ).


8
"Bu durumda, ilgili (örtük) sabit ifadeler 1! = 0 ve 2! = 0'dır, her ikisi de int değeri 1 olarak değerlendirilir" ... Bu aşırı karmaşık ve yanlıştır. Standart, kontrol ifadesinin whileskaler tipte olması gerektiğini ifade eder ve ifade 0 ile karşılaştırılana kadar döngü gövdesi tekrarlanır. Bu expr != 0, değerlendirilecek bir örtük olduğunu söylemez ... bu - 0 veya 1 - sırayla 0, ad infinitum ile karşılaştırılır. Hayır, ifade 0 ile karşılaştırılır, ancak bu karşılaştırma bir değer üretmez. PS Ben iptal ettim.
Jim Balter

3
@JimBalter: Ne demek istediğini anlıyorum ve cevabımı ele almak için cevabımı güncelleyeceğim. Demek istediğim, standardın "... kontrol ifadesi 0 ile karşılaştırılana kadar" ifadesinin değerlendirmeyi <expr> == 0; C'de "0'a eşittir" ifadesinin anlamı budur. Bu karşılaştırma, whiledöngünün anlambiliminin bir parçasıdır . Standartta ya da cevabımda, sonucun 0tekrar karşılaştırılması gerektiği konusunda herhangi bir ima yoktur . (Yazmak ==yerine yazmalıydım !=.) Ama cevabımın bu kısmı belli değildi ve güncelleyeceğim.
Keith Thompson

1
"" 0 ile karşılaştırır "C" anlamına gelir - ancak bu dil standarttır , C değil ... uygulama karşılaştırmayı yapar, bir C dili karşılaştırması oluşturmaz. "Her ikisi de int değerini 1 olarak değerlendirir" yazarsınız - ancak böyle bir değerlendirme gerçekleşmez. Eğer için oluşturulan koduna baktığımızda while (2), while (pointer), while (9.67), en naif, optimize edilmemiş derleyici tarafından, sen verim oluşturulur herhangi bir kod görmezsiniz 0ya 1. "! = Yerine == yazmalıydım - hayır, bu hiç mantıklı olmazdı.
Jim Balter

2
@JimBalter: Hmmm. "0'a eşittir" ... == 0ifadesinin bir C ifadesinin varlığını ima ettiğini söylemek istemiyorum . Demek istediğim, hem standardın whiledöngülerin açıklaması için gerekli olan "0'a eşittir" ve açık bir x == 0ifadenin mantıksal olarak aynı işlemi ima etmesi. Ve ben acı bir saf C derleyici herhangi bir gerçek derleyici oldukça bu kadar saf inanmıyorum rağmen - herhangi bir döngü için veya bir intdeğer üreten kod üretebilir düşünüyorum. 01while
Keith Thompson


141

Bir dakika bekle. Görüşmeci, bu adama benziyor muydu?

resim açıklamasını buraya girin

Görüşmecinin bu röportajda başarısız olması yeterince kötü , ya bu şirketteki diğer programcılar bu testi "geçtiyse"?

Hayır. İfadelerin değerlendirilmesi 1 == 0ve aynı derecede hızlı 2 == 0 olmalıdır . Biz hayal biri diğerinden daha hızlı olabilir zayıf derleyici uygulamaları. Ancak birinin diğerinden daha hızlı olması için iyi bir neden yoktur .

İddiaların doğru olacağı bazı belirsiz durumlar olsa bile, programcılar belirsiz (ve bu durumda ürpertici) bilgilerden hareketle değerlendirilmemelidir. Bu röportaj için endişelenmeyin, buradaki en iyi adım uzaklaşmaktır.

Feragatname: Bu orijinal bir Dilbert karikatürü DEĞİLDİR. Bu sadece bir karışım .


6
Bu soruya bir cevap da içermesi komik olurdu .
Cody Gray

hayır ama gerçekten, ciddi şirketler tarafından yazılan tüm derleyicilerin makul kod üreteceğini oldukça kolay bir şekilde hayal edebiliyoruz. "optimize edilmemiş kasa" / O0'ı alalım, belki anatolyg'in yayınladığı gibi sonuçlanacak. O zaman bu bir CPU sorunu, cmpişlenen 1'den 0'a 2'den 0'a kıyasla daha az döngüde çalışacak mı? cmp'yi genel olarak çalıştırmak için kaç döngü gerekir? bit örüntülerine göre değişken mi? yavaşlayan daha "karmaşık" bit kalıpları cmpmı? Şahsen bilmiyorum. 0'dan n'ye kadar kademeli olarak süper idiotik bir uygulama kontrolünü hayal edebilirsiniz (örn. n = 31).
v.oddou

5
Bu da benim açımdan: cmpişlenen 1 ve 200 için aynı derecede hızlı olmalıdır. Muhtemelen durum böyle olmayan aptal uygulamaları hayal edebiliriz . Ama birwhile(1) , daha hızlı olan aptal olmayan uygulamayıwhile(200) ? Benzer şekilde, bazı tarih öncesi çağlarda, mevcut tek uygulama böylesine aptalca ise, bugün bu konuda karışıklık yapmalı mıyız? Ben öyle düşünmüyorum, bu sivri saçlı patron konuşması ve gerçek bir mücevher!
janos

@ v.ouddou "cmp işlenen, 1'den 0'a 2'den 0'a kıyasla daha az döngüde çalışacaktır" - Hayır. Bir döngünün ne olduğunu öğrenmelisiniz. "Kişisel olarak bilmiyorum. 0'dan n'ye kadar kademeli olarak kontrol edilen süper bir aptalca uygulamayı hayal edebilirsin" ya da başka bir şekilde, görüşmeyi hala clueless bir aptal yaptı. Ve neden yavaş yavaş kontrol etme konusunda endişeleniyorsunuz? Uygulama, programınızı değerlendirmenin ortasında öğle yemeği molası vermeye karar veren bir kutudaki bir adam olabilir.
Jim Balter

79

Açıklamanız doğru. Bu, teknik bilgiye ek olarak özgüveninizi test eden bir soru gibi görünüyor.

Bu arada, eğer cevapladıysan

Her iki kod parçası da eşit derecede hızlıdır, çünkü her ikisinin de tamamlanması sonsuz zaman alır

görüşmeci söylerdi

Ancak while (1)saniyede daha fazla yineleme yapabilir; bana nedenini açıklayabilir misin? (bu saçmalık; güveninizi tekrar test etmek)

Yani sizin gibi cevap vererek, aksi takdirde bu kötü soruyu tartışmak için harcayacağınız zamandan tasarruf ettiniz.


İşte benim sistemimde derleyici tarafından oluşturulan örnek kod (MS Visual Studio 2012), optimizasyonlar kapalı:

yyy:
    xor eax, eax
    cmp eax, 1     (or 2, depending on your code)
    je xxx
    jmp yyy
xxx:
    ...

Optimizasyonlar açıkken:

xxx:
    jmp xxx

Böylece üretilen kod, en azından bir optimizasyon derleyicisiyle tamamen aynıdır.


28
Bu kod gerçekten derleyici benim sistem çıktı. Ben uydurmadım.
anatolyg

10
icepack "while için işlenen boole tipindedir" - mutlak saçmalık. Görüşmeci siz misiniz? Bu tür iddialarda bulunmadan önce C dili ve standardına aşina olmanızı öneririm.
Jim Balter

29
"Ben uydurmadım." - Lütfen saçma sapan konuşan icepack'e dikkat etmeyin. C'nin boolean türü yoktur (stdbool.h içinde _Bool vardır, ancak bu aynı değildir ve whileuzun önceliğin anlambilimi ) ve işleneni whileboolean veya _Bool veya başka herhangi bir özel tür değildir. Göreni whileolabilir herhangi ifadesi ... 0 halindeyken sonları ve non-0 devam ediyor.
Jim Balter

36
"Her iki kod parçası da aynı derecede hızlı, çünkü her ikisinin de tamamlanması sonsuz zaman alıyor" ilginç bir şey düşünmemi sağladı. Dan ifadeyi değiştirerek: biraz yüklü parçacık veya bozuk bir donanım saygısız olmak için sonsuz bir döngü sona erdirmek tek yolu olacaktır while (00000001) {}için while (00000000) {}. Değerler ne kadar doğru olursa, değerin yanlış değere çevrilme şansı o kadar az olur. Ne yazık ki, 2 de sadece bir gerçek bit var. Ancak, 3 daha uzun süre çalışır. Bu sadece bunu her zaman optimize etmeyen bir derleyici için de geçerlidir (VC ++).
Jonathan Dickinson

8
@ mr5 hayır. Biraz çevirmenin aslında böyle bir şeyle sonuçlanması için on binlerce yıl içinde yürütme sürelerinden bahsediyorsunuz. Sadece bir düşünce deneyi. Ölümsüz bir ırktan gelirseniz, bit çevirmenin programınızı etkilemesini önlemek için -1'i kullanmak isteyebilirsiniz.
Jonathan Dickinson

60

Soru için en olası açıklama, görüşmecinin, işlemcinin sıfır olmayan bir değere ulaşana kadar sayıların ayrı ayrı bitlerini tek tek kontrol ettiğini düşünmesidir:

1 = 00000001
2 = 00000010

"Sıfır mı?" Algoritma, sayının sağ tarafından başlar ve sıfır olmayan bir bite ulaşana kadar her biti kontrol etmek zorundadır, while(1) { }döngü yineleme başına while(2) { }döngüden iki kat daha fazla biti kontrol etmelidir.

Bu, bilgisayarların nasıl çalıştığına dair çok yanlış bir zihinsel model gerektirir, ancak kendi iç mantığı vardır. Çek bir yolu sormak olurdu while(-1) { }ya while(3) { }eğer eşit hızlı olacaktır veya while(32) { }olacağını bile yavaş .


39
Görüşmecinin yanlış anlaşılmasının daha çok "2 koşullu bir ifadede kullanılabilmesi için boole dönüştürülmesi gereken bir int, 1 ise zaten boole olduğu" şeklinde olacağını varsaydım.
Russell Borogove

7
Ve karşılaştırma algoritması soldan başlarsa, tam tersi olur.
Paŭlo Ebermann

1
+1, ben de öyle düşünmüştüm. birisinin cmpalgoritmasının temelde ilk farkta erken döngü çıkışı olan doğrusal bir bit kontrolü olduğuna inanan birini mükemmel bir şekilde hayal edebilirsiniz .
v.oddou

1
@PeterCordes "Hiç kimsenin (sizden başka) gcc ya da clang -O0çıktısının yeterince gerçek olmadığını iddia ettiğini duymadım ." Hiç böyle bir şey söylemedim ve aklımda gcc veya clang yoktu. Beni yanlış okumalısın. MSVC'nin ürettiği şeyin çok komik olduğunu düşünmüyorum.
blubberdiblub

1
@PeterCordes Yanılmışım, MSVC'de while(1)döngüden önce değil, ifadede bir kesme noktası . Ancak, ifadeyi optimize ederken döngü içinde hala çöker. Al bu kodu sonları dolu. Unoptimized ayıklama modunda olsun bu . Optimize ederken, birçok kesme noktası birlikte düşer veya hatta bir sonraki fonksiyona dökülür (IDE, hata ayıklama sırasında sonuç kesme noktalarını gösterir) - ilgili sökme .
blubberdiblub

32

Tabii ki bu menajerin gerçek niyetlerini bilmiyorum, ama tamamen farklı bir görüş öneriyorum: Bir takıma yeni bir üye alırken, çatışma durumlarına nasıl tepki verdiğini bilmek faydalıdır.

Sizi çatışmaya sürüklediler. Eğer bu doğruysa, zekiler ve soru iyiydi. Bankacılık gibi bazı endüstriler için sorununuzu Stack Overflow'a göndermek reddetme için bir neden olabilir.

Ama elbette bilmiyorum, sadece bir seçenek öneriyorum.


Gerçekten mükemmel ama (2) vs while (1) açıkça dilbert çizgi romanlarından alınmıştır. Doğru zihninde biri tarafından icat edilemez (zaten kimse (2) yazmak için olası bir şey olarak nasıl ortaya çıkar?). Eğer hipoteziniz doğru olsaydı, kesinlikle o kadar benzersiz bir sorun verecektiniz ki, Google için. "While (0xf00b442) while (1) 'den daha yavaş ise, banka aksi takdirde inerviewee'nin sorusunu nasıl bulabilir? bunların NSA olduklarını ve keycore'a erişebildiklerini düşünüyor musunuz?
v.oddou

25

Bence ipucu "üst düzey bir yönetici tarafından sorulan" bölümünde bulunacak. Bu kişi yönetici olduğu zaman programlamayı durdurdu ve üst düzey yönetici olması birkaç yılını aldı. Programlamaya olan ilginizi hiçbir zaman kaybetmedim, ama o günden beri hiç bir satır yazmadı. Bu yüzden referansı, bazı cevapların belirttiği gibi "orada iyi bir derleyici" değil, "bu kişinin 20-30 yıl önce çalıştığı derleyici" dir.

O zamanlar, programcılar zamanlarının önemli bir yüzdesini kodlarını daha hızlı ve daha verimli hale getirmek için çeşitli yöntemleri denemek için harcadılar çünkü 'merkezi minibilgisayar'ın CPU zamanı çok değerli. İnsanlar derleyiciler yazıyor. Şirketinin o sırada kullanıma sunulan tek ve tek derleyicisinin 'optimize edilebilen sık karşılaşılan ifadeler' temelinde optimize edildiğini ve bir süre karşılaştığında bir kısayol aldığını tahmin ediyorum (1) ve her şeyi değerlendirdi bir süre dahil olmak üzere (2). Böyle bir deneyime sahip olmak, konumunu ve ona olan güvenini açıklayabilir.

Sizi işe almak için en iyi yaklaşım muhtemelen üst düzey yöneticinin taşınmasını ve sizden önce "programlama eski güzel günlerinde" 2-3 dakika ders vermek sağlayan bir yaklaşımdır sonraki görüşme konusuna sorunsuz bir şekilde yönlendirmeden sağlayan yöntemdir. (Burada iyi zamanlama önemlidir - çok hızlı ve hikayeyi kesiyorsunuz - çok yavaş ve yetersiz odaklanmış biri olarak etiketlenmişsiniz). Röportajın sonunda bu konu hakkında daha fazla bilgi edinmek isteyeceğinizi söyleyin.


19

Ona bu sonuca nasıl ulaştığını sormalıydın. Orada iyi bir derleyici altında, iki aynı asm talimatları derlemek. Yani, derleyiciye de yola çıkmasını söylemeliydi. Ve buna rağmen, teorik eğitimli bir tahmin yapmak için derleyiciyi ve platformu çok iyi bilmeniz gerekir. Ve sonunda, pratikte önemli değil, çünkü döngüyü bu ayrıntıdan daha fazla etkileyecek bellek parçalanması veya sistem yükü gibi başka dış faktörler var.


14
@GKFX Cevabınızı verdiyseniz ve size yanlış olduğunu söylüyorlarsa, nedenini açıklamalarını isteyememeniz için hiçbir neden yoktur. Anatolyg doğruysa ve bu kendinize olan güveninizin bir testiyse, o zaman neden yaptığınız şekilde cevapladığınızı ve aynı şeyi sorduğunuzu açıklamalısınız.
P.Turpie

Onlara ilk söylediğin şey demek istedim. "Neden x daha hızlı?" "Bilmiyorum; neden x daha hızlı?". Açıkçası, doğru cevap verdikten sonra sorabilirsiniz.
GKFX

18

Bu soru uğruna, C Komitesinden Doug Gwyn'i optimize edici geçişi olmayan bazı erken C derleyicilerinin montaj için bir test oluşturacağını yazdığını hatırlamalıyım while(1)(buna kıyasla for(;;)).

Bu tarihsel notu vererek görüşmeciye cevap verirdim ve daha sonra herhangi bir derleyicinin bunu yapmasına şaşırmış olsam bile, bir derleyicinin şunları yapabileceğini söyleyebilirim:

  • optimizer geçmek olmadan derleyici hem bir test oluşturmak while(1)vewhile(2)
  • optimizer pass ile derleyiciye tümünün (koşulsuz atlama ile) while(1)deyimsel olduğu düşünülür. Bu while(2)bir test ile bırakılır ve bu nedenle ikisi arasında bir performans farkı yaratır.

Ben tabii düşünmediğini o görüşmeci eklersiniz while(1)ve while(2)bu eşdeğer yapılar gibi aynı yapı, düşük kaliteli optimizasyonu bir işaretidir.


10

Böyle bir soru üzerine başka bir şey, yöneticinize yanlış olduğunu söylemek için cesaretin olup olmadığını görmek olacaktır! Ve ne kadar yumuşak bir şekilde iletişim kurabileceğiniz.

İlk içgüdüm, yöneticiye iyi bir derleyicinin ilgilenmesi gerektiğini göstermek için montaj çıktısı oluşturmak olurdu ve eğer bunu yapmazsa, bunun için bir sonraki yamayı göndereceksiniz :)


8

Bu kadar çok insanın bu sorunu araştırdığını görmek için bunun ne kadar hızlı bir şekilde mikro optimizasyon yapmak istediğinizi görmek için neden bir test olabileceğini tam olarak gösterir. şeyleri .

Cevabım; o kadar önemli değil, çözdüğümüz iş sorununa odaklanmayı tercih ediyorum. Sonuçta, bunun için bana ödeme yapılacak.

Dahası, while(1) {} çünkü daha yaygın ve diğer takım arkadaşlarının birisinin neden 1'den daha yüksek bir sayıya gideceğini anlamak için zaman harcamaları gerekmeyecekti.

Şimdi git ve biraz kod yaz. ;-)


1
Çalışma süresi taleplerine uyması için sadece 1 veya 2 milisaniyelik tıraş etmeniz gereken bazı gerçek zamanlı kodları optimize etmeniz için ödeme yapılmadığı sürece. Tabii ki bu optimize edici için bir iş, diyebilir ki - yani mimariniz için bir optimize ediciniz varsa.
Neowizard

6

Optimizasyon konusunda endişeleniyorsanız,

for (;;)

çünkü bunun hiç testi yok. (alaycı mod)


2
Bu yüzden kullanımı akıllıca while(2), optimizasyon için yer bırakıyor, daha sonra for (;;)performans artışı için hazır olduğunuzda geçiş yapıyorsunuz.
Groo

5

Bana öyle geliyor ki, bu teknik bir soru olarak maskelenen davranışsal röportaj sorularından biri. Bazı şirketler bunu yapar - herhangi bir yetkili programcının cevaplaması oldukça kolay olan teknik bir soru soracaklar, ancak görüşmeci doğru cevabı verdiğinde, görüşmeci onlara yanlış olduklarını söyleyecektir.

Şirket bu durumda nasıl tepki vereceğinizi görmek istiyor. Sessizce oturup sessizce mi oturuyorsunuz ya da kendinizden şüphe duyuyorsanız ya da görüşmeciyi üzme korkusu nedeniyle cevabınızın doğru olduğunu zorlamıyor musunuz? Yoksa yanıldığını bildiğiniz bir otoriteye meydan okumaya istekli misiniz? Mahkumiyetlerinizi desteklemeye istekli olup olmadığınızı ve bunu dokunsal ve saygılı bir şekilde yapıp yapamayacağınızı görmek istiyorlar.


3

Bu saçmalık fark yarattığında C ve Assembly kodunu tekrar programlardım. Bir fark yarattığında bunu Mecliste yazdık.

Bu soru bana sorulursa, Donald Knuth'un 1974'teki ünlü optimizasyonunu erken optimizasyon hakkında tekrar ederdim ve görüşmeci gülmez ve devam etmezse yürürüm.


1
Ayrıca, "Yerleşik mühendislik disiplinlerinde, kolayca elde edilen,% 12'lik bir iyileşmenin asla marjinal olduğu düşünülmüyor ve yazılım mühendisliğinde aynı bakış açısının geçerli olması gerektiğine inanıyorum" dediğinde, yürüyüşün haksız olduğunu düşünüyorum.
Alice

3

Belki görüşmeci böylesine aptalca bir soru sordu ve 3 puan vermenizi istedi:

  1. Temel akıl yürütme.Her iki döngü de sonsuzdur, performans hakkında konuşmak zordur.
  2. Optimizasyon seviyeleri hakkında bilgi.Derleyicinin sizin için herhangi bir optimizasyon yapmasına izin verirseniz, özellikle blok boş değilse durumu optimize eder.
  3. Mikroişlemci mimarisi hakkında bilgi. Çoğu mimarinin 0 ile karşılaştırmak için özel bir CPU talimatı vardır (her zaman daha hızlı olmasa da).

2

Sorun şu: Eğer gerçekten bir program yazıp hızını ölçerseniz, her iki devrenin hızı da farklı olabilir! Makul bir karşılaştırma için:

unsigned long i = 0;
while (1) { if (++i == 1000000000) break; }

unsigned long i = 0;
while (2) { if (++i == 1000000000) break; }

zamanı yazdıran bazı kodlar eklendiğinde, döngünün bir veya iki önbellek satırına nasıl yerleştirildiği gibi bazı rastgele efektler fark yaratabilir. Bir döngü saf bir şekilde tamamen bir önbellek satırında veya bir önbellek satırının başında olabilir veya iki önbellek satırının üstünde olabilir. Sonuç olarak, görüşmecinin en hızlı iddia ettiği şey aslında tesadüfen en hızlı olabilir.

En kötü durum senaryosu: Optimize edici bir derleyici, döngünün ne yaptığını anlamaz, ancak ikinci döngü yürütüldüğünde üretilen değerlerin birincisi tarafından üretilenlerle aynı olduğunu anlar. Ve ilk döngü için tam kod üretin, ancak ikinci döngü için değil.


1
"Önbellek satırları" mantığı yalnızca çok küçük bir önbelleğe sahip bir yonga üzerinde çalışacaktır.
sharptooth

10
Bu konunun yanında. Hızla ilgili sorular "diğer her şeyin eşit" olduğunu varsayar.
Jim Balter

6
@JimBalter: Bu bir hız sorunu değil, bir görüşmeci ile yapılan bir tartışma hakkında bir soruydu. Ve gerçek bir test yapmanın, görüşmecinin argümanı ile ilgisi olmayan ancak saf tesadüf olan nedenlerden dolayı "doğru" olduğunu kanıtlaması olasılığı. Eğer onun yanlış olduğunu kanıtlamaya çalışırsanız, bu sizi utanç verici bir duruma sokar.
gnasher729

1
@ gnasher729 Tüm mantıksal argümanlar bir yana, bahsettiğiniz tesadüf vakası incelenmeye değer olacaktır. Ancak hala böyle bir vakanın varlığına körü körüne inanmak sadece naif değil aynı zamanda aptaldır. Bunun ne olduğunu, nasıl veya neden olacağını açıklamadığınız sürece bu cevap işe yaramaz.
user568109

4
@ gnasher729 "Bu bir hız sorunu değildi" - Dürüst olmayan retorik teknikler kullanan insanları tartışmayacağım.
Jim Balter

2

İkisi de eşit - aynı.

Spesifikasyonlara göre, 0 olmayan bir şey doğru olarak kabul edilir, bu yüzden herhangi bir optimizasyon olmadan bile ve iyi bir derleyici while (1) veya while (2) için herhangi bir kod üretmez. Derleyici basit bir kontrol oluşturur != 0.


@djechlin - çünkü ikisi de 1 cpu döngüsü alıyor.
UncleKing

Derleyici sabiti katlanır, bu nedenle çalışma zamanında değerlendirilmez.
PaulHK

2

İnsanların bu çok basit soruyu test etmek, kanıtlamak ve cevaplamak için harcadıkları zaman ve çaba miktarına bakarak, her ikisinin de soruyu sorarak çok yavaş yapıldığını söylüyorum.

Ve böylece daha fazla zaman geçirmek için ...

"while (2)" çok saçma, çünkü,

"while (1)" ve "while (true)", tarihsel olarak, kesinlikle gerçekleşecek bir koşula bağlı olarak, döngü içinde bir aşamada "break" denilmesini bekleyen sonsuz bir döngü oluşturmak için kullanılır.

"1" her zaman doğruyu değerlendirmek için oradadır ve bu nedenle "while (2)" demek, doğru olarak değerlendirilecek "while (1 + 1 == 2)" demek kadar saçmadır.

Ve tamamen aptal olmak istiyorsanız sadece kullanın: -

while (1 + 5 - 2 - (1 * 3) == 0.5 - 4 + ((9 * 2) / 4)) {
    if (succeed())
        break;
}

Kodlayıcınızın kodun çalışmasını etkilemeyen bir yazım hatası yaptığını düşünmek istiyorum, ama kasıtlı olarak "2" yi sadece garip olmak için kullandıysa, kodunuzu kullanarak garip sh! T'yi zorlaştırmadan önce onu çuvalla okuyun ve çalışın.


Geri dönüşleri yaptığınız geri alma işlemi çok yüksek rep kullanıcısı tarafından düzenlenir. Bu insanlar genellikle politikaları çok iyi biliyorlar ve size bunları öğretmek için buradalar. Yayınınızın son satırını, yayınınıza yararlı bir şey eklemediğini görüyorum. Açıkçası eksik olduğum şakayı alsam bile, fazladan paragrafa değmeyecek kadar konuşkan olurdum.
Palec

@Palec: Yorum için teşekkürler. Ben aynı adam çoğunlukla benim oturum kaldırmak için, benim yazı birçok düzenledi bulundu. Ben de onun sadece bir itibar trolü olduğunu ve bu yüzden de onun itibarını anladım. Çevrimiçi forumlar dili ve ortak nezaketleri o kadar çok tüketti ki artık yazılarımızı imzalamıyoruz? belki biraz eski bir okulum ama hellosları ve vedaları atlamak kaba görünüyor. Uygulamaları kullanıyoruz, ama biz hala insanız.
ekerner

1
On Stack Borsası , saygılarımla, reklam sloganı, teşekkürler vb kabul edilmiyor . Aynı şey yardım merkezinde , özellikle beklenen davranışlar altında belirtilmiştir . Yığın Değişimi'nin bir parçası değil, Yığın Taşması bile bir forum değil - bunlar Soru-Cevap siteleridir. Düzenleme farklılıklardan biridir. Ayrıca yorumlar tartışma için değil, yalnızca gönderi hakkında geri bildirim sağlamak için kullanılmalıdır ( Yığın Taşması Sohbeti ). Soru ve Cevapların bir forumdan farklı birçok yolu vardır. Bundan da üzerinde yardım merkezinin ve üzerinde Meta yığın taşması .
Palec

2000'den fazla temsilciniz (düzenleme ayrıcalığınız) olduğunda, düzenlemelerden daha fazla temsil edemeyeceğinizi unutmayın. Şüphelendiğinizde ve katılmamanız gereken düzenleme yayınınıza uygulandıysa veya birisinin hatalı davranış gördüğünü gördüğünüzde Meta Stack Overflow'u sorun . Editör yanlış bir şey yaptıysa, bir mod (belki de fark etmediler) tarafından bilgilendirilebilir veya hatta bir şekilde cezalandırılabilir (davranış kasıtlı olarak kötü niyetli ise). Aksi takdirde, düzenlemenin / davranışın neden doğru olduğunu gösteren işaretçiler alırsınız. Gereksiz geri alma, düzeltme geçmişini keser ve sizi geri alma savaşına sokabilir. Yalnızca düzenlemenin yanlış olduğundan emin olduğunda geri alırım.
Palec

Son olarak imzalama, selamlama,…: Bu formaliteleri içermemek kaba görünebilir, ancak sinyal-gürültü oranını arttırır ve hiçbir bilgi kaybolmaz. İstediğiniz herhangi bir takma adı seçebilirsiniz, bu sizin imzanızdır. Çoğu yerde avatarınız da var.
Palec

1

Bu derleyiciye bağlıdır.

Kodu optimize ederse veya belirli bir komut seti için aynı sayıda talimatla 1 ve 2'yi true olarak değerlendirirse, yürütme hızı aynı olacaktır.

Gerçek durumlarda her zaman eşit derecede hızlı olacaktır, ancak farklı değerlendirildiğinde belirli bir derleyiciyi ve belirli bir sistemi hayal etmek mümkün olacaktır.

Demek istediğim: bu gerçekten dil (C) ile ilgili bir soru değil.


0

Bu soruyu cevaplamak isteyen insanlar en hızlı döngüyü istediklerinden, diğer cevaplarda belirtildiği gibi, her ikisinin de aynı derleme koduna eşit olarak derlendiğini yanıtlardım. Bununla birlikte, görüşmeciye 'döngü çözme' seçeneğini önerebilirsiniz ; a yerine {} while döngüsü yerine while döngüsü.

Dikkatli: Döngünün en azından her zaman bir kez çalışacağından emin olmanız gerekir .

İlmeğin içinde bir kırılma durumu olmalıdır.

Ayrıca bu tür bir döngü için kişisel olarak do {} kullanırken (42) 0 hariç herhangi bir tamsayı işi yapacağını tercih ederim.


Neden bir {} while döngüsü önerdi? While (1) (veya while (2)) aynı şeyi yapar.
Catsunami

bir ekstra atlama kaldırır daha iyi performans. Tabii ki, döngü en az bir kez yürütüleceğini bildiğiniz durumda
Antonin GAVREL

0

Açık cevap: yayınlandığı gibi, her iki parça da eşit derecede meşgul sonsuz bir döngü çalıştıracak ve bu da programı sonsuz derecede yavaşlatacaktır .

C anahtar kelimelerini makrolar olarak yeniden tanımlamak teknik olarak tanımlanmamış davranışa sahip olsa da, kod parçacıklarından birini hızlı yapmanın tek yolu budur: Bu satırı 2 parçanın üstüne ekleyebilirsiniz:

#define while(x) sleep(x);

gerçekten while(1)iki kat daha hızlı (veya yarı yavaş) yapar while(2).


@MaxB: gerçekten de makro hile daha da çarpık olmalıdır. Yeni sürümün C Standardı tarafından garanti edilmemesine rağmen çalışması gerektiğini düşünüyorum.
chqrlie

-4

Neden while(2)daha yavaş olacağını düşünebilmemin tek nedeni :

  1. Kod, döngüyü

    cmp eax, 2

  2. Çıkarma gerçekleştiğinde esasen

    a. 00000000 - 00000010 cmp eax, 2

    onun yerine

    b. 00000000 - 00000001 cmp eax, 1

cmpyalnızca bayrakları ayarlar ve bir sonuç belirlemez. Yani en az önemli bitlerde b ile ödünç almamız gerekip gerekmediğini biliyoruz . İle Halbuki bir sen bir ödünç almadan önce iki çıkarmalar gerçekleştirmek zorunda.


15
cmp her iki durumda da 1 cpu döngüsü alacaktır.
UncleKing

8
Bu kod yanlış olur. Doğru kod kayıt
eax'a
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.