Go nasıl bu kadar çabuk derlenir?


217

Googled'i ve Go web sitesini araştırdım, ancak Go'nun olağanüstü oluşturma süreleri için bir açıklama bulamıyorum. Bunlar dil özelliklerinin (veya eksikliğinin) ürünleri mi, son derece optimize edilmiş bir derleyici mi, yoksa başka bir şey mi? Go'yu tanıtmaya çalışmıyorum; Ben sadece merak ediyorum.


12
@Destek, bunun farkındayım. Bir derleyiciyi farkedilir bir çabuklukla derleyecek şekilde uygulamanın, erken optimizasyondan başka bir şey olduğunu düşünüyorum. Muhtemelen, iyi yazılım tasarımı ve geliştirme uygulamalarının sonucunu temsil eder. Ayrıca, Knuth'un sözlerinin bağlamdan çıkarıldığını ve yanlış uygulandığını göremiyorum.
Adam Crossland

55
Kötümserlerin bu sorunun versiyonu "C ++ neden bu kadar yavaş derleniyor?" stackoverflow.com/questions/588884/…
dan04

14
Bu soruyu görüşe dayalı olmadığı için yeniden açmaya oy verdim. Tesis derleme hızına sahip olan dil ve / veya derleyici seçimleri hakkında iyi bir teknik (görüş belirtilmemiş) genel bakış verilebilir.
Martin Tournoij

Küçük projeler için Go bana yavaş geliyor. Çünkü Turbo-Pascal'ın muhtemelen binlerce kat daha yavaş olan bir bilgisayarda çok daha hızlı olduğunu hatırlıyorum. prog21.dadgum.com/47.html?repost=true . Ne zaman "go build" yazsam ve birkaç saniye boyunca hiçbir şey olmuyorsa, eski Fortran derleyicilerine ve delikli kartlara dönüyorum. YMMV. TLDR: "yavaş" ve "hızlı" göreli terimlerdir.
RedGrittyBrick

Kesinlikle daha ayrıntılı bilgi için dave.cheney.net/2014/06/07/five-things-that-make-go-fast okumanızı öneririz
Karthik

Yanıtlar:


193

Bağımlılık analizi.

Git SSS şu cümle yer için kullanılır:

Go, bağımlılık analizini kolaylaştıran ve C-tarzı dosya ve kütüphaneleri içeren ek yükün çoğunu önleyen yazılım yapımı için bir model sağlar.

Cümle artık SSS bölümünde yer almasa da , bu konu C / C ++ ve Go'nun bağımlılık analiz yaklaşımını karşılaştıran Google'da Go konuşmasında ayrıntılı olarak açıklanmaktadır.

Hızlı derlemenin ana nedeni budur. Ve bu tasarım gereğidir.


Bu ifade artık Git SSS'sinde değil, ancak C / C ++ ve Pascal / Modula / Go yaklaşımını karşılaştıran "bağımlılık analizi" konusuna ilişkin daha ayrıntılı bir açıklama Google'daki Go
14'te rob74

76

Sanırım Go derleyicileri hızlı değil , diğer derleyiciler yavaş .

C ve C ++ derleyicileri çok büyük miktarda başlık ayrıştırmak zorunda - örneğin, C ++ "merhaba dünya" derlemek neredeyse yarım megabayt kaynak olan 18k kod satırı derlemek gerektirir!

$ cpp hello.cpp | wc
  18364   40513  433334

Java ve C # derleyicileri bir VM'de çalışır, yani herhangi bir şey derlemeden önce işletim sisteminin tüm VM'yi yüklemesi gerekir, o zaman bayt kodundan yerel koda JIT derlenmesi gerekir, bu da biraz zaman alır.

Derleme hızı birkaç faktöre bağlıdır.

Bazı diller hızlı bir şekilde derlenecek şekilde tasarlanmıştır. Örneğin, Pascal tek geçişli bir derleyici kullanılarak derlenecek şekilde tasarlanmıştır.

Derleyicilerin kendisi de optimize edilebilir. Örneğin, Turbo Pascal derleyicisi, dil tasarımı ile birleştiğinde, 286 sınıfı bir donanım üzerinde çalışan çok hızlı bir derleyici ile sonuçlanan, elle optimize edilmiş montajcıda yazılmıştır. Şimdi bile modern Pascal derleyicilerinin (örneğin FreePascal) Go derleyicilerinden daha hızlı olduğunu düşünüyorum.


19
Microsoft'un C # derleyicisi bir VM'de çalışmaz. Hala performans nedenleriyle C ++ ile yazılmıştır.
blucz

19
Turbo Pascal ve daha sonra Delphi, şaşırtıcı derecede hızlı derleyiciler için en iyi örneklerdir. Her ikisinin mimarı Microsoft'a taşındıktan sonra, hem MS derleyicilerinde hem de dillerde büyük gelişmeler gördük. Bu rastgele bir tesadüf değil.
TheBlastOne

7
18k satır (tam olarak 18364) kod 433334 bayttır (~ 0,5MB)
el.pescado

9
C # derleyicisi 2011'den beri C # ile derlenmiştir. Daha sonra herkesin okuyacağı bir güncelleme.
Kurt Koller

3
Ancak oluşturulan MSIL çalıştıran C # derleyicisi ve CLR farklı şeylerdir. CLR'nin C # ile yazılmadığından oldukça eminim.
jocull

39

Go derleyicisinin çoğu C / C ++ derleyicisinden çok daha hızlı olmasının birçok nedeni vardır:

  • En önemli neden : C / C ++ derleyicilerinin çoğu son derece kötü tasarımlar sergiler (derleme hızı açısından). Ayrıca, derleme hızı açısından, C / C ++ ekosisteminin bazı bölümleri (programcıların kodlarını yazdığı editörler gibi) derleme hızı göz önünde bulundurularak tasarlanmamıştır.

  • En önemli neden : Hızlı derleme hızı, Go derleyicisinde ve Go dilinde bilinçli bir seçimdi

  • Go derleyicisinin C / C ++ derleyicilerinden daha basit bir iyileştiricisi vardır

  • C ++ 'dan farklı olarak, Go'nun şablonları ve satır içi işlevleri yoktur. Bu, Go'nun herhangi bir şablon veya işlev örneği gerçekleştirmesi gerekmediği anlamına gelir.

  • Go derleyicisi daha düşük düzeyli derleme kodu oluşturur ve eniyileştirici derleme kodunda çalışır, tipik bir C / C ++ derleyicisinde ise eniyileme orijinal kaynak kodunun dahili bir temsili üzerinde çalışır. C / C ++ derleyicisindeki ekstra yük, dahili gösterimin oluşturulması gerektiğinden gelir.

  • Bir Go programının son bağlantısı (5l / 6l / 8l), bir C / C ++ programını bağlamaktan daha yavaş olabilir, çünkü Go derleyicisi kullanılan derleme kodunun tümünü kullanıyor ve belki de C / C ++ bağlayıcılar yapmıyor

  • Bazı C / C ++ derleyicileri (GCC) metin biçiminde (montajcıya iletilecek) talimatlar üretirken, Go derleyicisi ikili biçimde talimatlar üretir. Metni ikiliye dönüştürmek için fazladan (ancak çok değil) bir iş yapılması gerekir.

  • Go derleyicisi çok az sayıda CPU mimarisini hedeflerken, GCC derleyicisi çok sayıda CPU'yu hedefliyor

  • Jikes gibi yüksek derleme hızı hedefiyle tasarlanan derleyiciler hızlıdır. 2GHz CPU'da, Jikes saniyede 20000'den fazla Java kodu satırı derleyebilir (ve artan derleme modu daha da verimlidir).


17
Go'nun derleyicisi küçük işlevleri sıralar. Az sayıda CPU'yu hedeflemenin sizi daha yavaş hale getirdiğinden emin değilim ... x86 için derlerken gcc'nin PPC kodu üretmediğini varsayıyorum.
Brad Fitzpatrick

@BradFitzpatrick eski bir yorumu diriltmekten nefret ediyor, ancak daha az sayıda platformu hedefleyerek derleyicinin geliştiricileri her biri için optimize etmek için daha fazla zaman harcayabilir.
Sebat

bir ara form kullanmak, çok daha fazla mimariyi desteklemenizi sağlar, çünkü şimdi her yeni mimari için yeni bir arka uç
yazmanız gerekiyor

34

Derleme verimliliği önemli bir tasarım hedefiydi:

Son olarak, hızlı olması amaçlanmıştır: tek bir bilgisayarda büyük bir yürütülebilir dosya oluşturmak en fazla birkaç saniye sürmelidir. Bu hedeflere ulaşmak için bir dizi dil sorununu ele almak gerekiyordu: etkileyici ama hafif bir tip sistemi; eşzamanlılık ve çöp toplama; katı bağımlılık özellikleri; ve bunun gibi. SSS

Dil SSS, ayrıştırma ile ilgili belirli dil özellikleri açısından oldukça ilginçtir:

İkincisi, dil analiz edilmesi kolay olacak şekilde tasarlanmıştır ve sembol tablosu olmadan ayrıştırılabilir.


6
Bu doğru değil. Go kaynak kodunu sembol tablosu olmadan tam olarak ayrıştıramazsınız.

12
Ayrıca çöp toplama işleminin neden derleme sürelerini artırdığını anlamıyorum. Sadece değil.
TheBlastOne

3
Bunlar SSS'den alıntılar: golang.org/doc/go_faq.html Hedeflerine ulaşamayacaklarını (sembol tablosu) veya mantıklarının hatalı olup olmadığını (GC) söyleyemem.
Larry OBrien

5
@FUZxxl gidin golang.org/ref/spec#Primary_expressions ve iki dizileri [Operand, Çağrı] ve [Dönüşüm] düşünün. Örnek Git kaynak kodu: tanımlayıcı1 (tanımlayıcı2). Sembol tablosu olmadan bu örneğin bir çağrı mı yoksa dönüşüm mü olduğuna karar vermek imkansızdır. | Herhangi bir dil bir dereceye kadar sembol tablosu olmadan ayrıştırılabilir. Go kaynak kodlarının çoğunun bir sembol tablosu olmadan ayrıştırılabileceği doğrudur, ancak golang spec'te tanımlanan tüm dilbilgisi öğelerini tanımanın mümkün olmadığı doğru değildir.

3
@Atom Ayrıştırıcının bir hata bildiren kod parçası olmasını önlemek için çok çalışıyorsunuz. Ayrıştırıcılar genellikle tutarlı hata mesajlarını bildirme konusunda zayıf bir iş çıkarır. Burada, ifade aTypeiçin değişken bir başvuru gibi bir ayrıştırma ağacı oluşturursunuz ve daha sonra anlamsal analiz aşamasında, o zaman anlamlı bir hata yazdırmamanız gerektiğini öğrendiğinizde.
Sam Harwell

26

Yukarıdakilerin çoğu doğru olsa da, gerçekten bahsetmeyen çok önemli bir nokta var: Bağımlılık yönetimi.

Git yalnızca ithal olduğunu paketleri eklemesi gereken doğrudan (zaten neyi ithal olarak onlar gerekmez). Bu, her bir dosyanın y başlıkları vb. İçeren x üstbilgileri de dahil olmak üzere başladığı C / C ++ ile tam bir zıttır . Alt satır: Go'nun derlenmesi, C / C ++ 'nın üstel zaman aldığı ithal paketlerin sayısı ile doğrusal zamanı alır.


22

Bir derleyicinin çeviri verimliliği için iyi bir test kendi kendine derleme: belirli bir derleyicinin kendini derlemesi ne kadar sürer? C ++ için çok uzun zaman alır (saat?). Karşılaştırıldığında, bir Pascal / Modula-2 / Oberon derleyici kendini modern bir makinede bir saniyeden daha kısa sürede derleyecektir [1].

Go bu dillerden ilham almıştır, ancak bu verimliliğin temel nedenlerinden bazıları şunlardır:

  1. Etkili tarama ve ayrıştırma için matematiksel olarak sağlam, açıkça tanımlanmış bir sözdizimi.

  2. C / C ++ gibi bağımsız derlemenin aksine, başlık dosyalarının gereksiz yere yeniden okunmasını ve diğer modüllerin yeniden derlenmesini önlemek için modül sınırları boyunca bağımlılık ve tür denetimi ile ayrı derleme kullanan, tür güvenli ve statik olarak derlenmiş bir dil. derleyici tarafından böyle bir çapraz modül kontrolü yapılmaz (bu nedenle basit bir tek satırlık "merhaba dünya" programı için bile tüm bu başlık dosyalarını tekrar tekrar okuma ihtiyacı).

  3. Tabii ki yukarıdaki 1 ve 2. noktalarda büyük ölçüde yardımcı olan verimli bir derleyici uygulaması (örneğin, tek geçişli, yinelemeli iniş yukarıdan aşağıya ayrıştırma).

Bu ilkeler 1970 ve 1980'lerde Mesa, Ada, Modula-2 / Oberon ve diğerleri gibi dillerde zaten biliniyor ve tam olarak uygulanıyor ve sadece şimdi (2010'larda) Go (Google) gibi modern dillere doğru yol alıyor , Swift (Apple), C # (Microsoft) ve diğerleri.

Bunun yakında istisna değil norm olacağını umalım. Oraya ulaşmak için iki şeyin olması gerekir:

  1. İlk olarak, Google, Microsoft ve Apple gibi yazılım platformu sağlayıcıları, uygulama geliştiricilerini yeni derleme yöntemini kullanmaya teşvik ederken, mevcut kod tabanlarını yeniden kullanmalarını sağlayarak başlamalıdır. Apple şimdi Objective-C ile aynı anda varolabilen Swift programlama diliyle yapmaya çalışıyor (aynı çalışma ortamı kullandığından).

  2. İkincisi, temeldeki yazılım platformlarının kendileri, zaman içinde bu ilkeleri kullanarak zaman içinde yeniden yazılmalı, aynı zamanda süreçte modül hiyerarşisini daha az monolitik hale getirmek için yeniden tasarlanmalıdır. Bu elbette mamut bir görevdir ve on yılın daha iyi bir kısmını alabilir (aslında bunu yapmak için yeterince cesurlarsa - Google konusunda hiç emin değilim).

Her durumda, dilin benimsenmesini sağlayan platform, tersi değil.

Referanslar:

[1] http://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.System.pdf , sayfa 6: "Derleyici kendini yaklaşık 3 saniye içinde derler". Bu teklif, 25 MHz saat frekansında çalışan ve 1 MByte ana bellek içeren düşük maliyetli Xilinx Spartan-3 FPGA geliştirme kartı içindir. Bundan 1 GHz'in üzerinde bir saat frekansında ve birkaç GByte ana bellekten (yani Xilinx Spartan-3 FPGA kartından daha güçlü birkaç büyüklükte siparişlerde) çalışan modern bir işlemci için kolayca "1 saniyeden daha azına" gidebilir , G / Ç hızları dikkate alındığında bile. Zaten 1990'da Oberon 2-4 MBytes ana belleğe sahip 25MHz NS32X32 işlemcide çalıştırıldığında, derleyici sadece birkaç saniye içinde derlendi. Aslında bekleme kavramıderleyicinin bir derleme döngüsünü bitirmesi için Oberon programcıları o zaman bile tamamen bilinmiyordu. Tipik programlar için, derleme komutunu tetikleyen fare düğmesinden parmağın kaldırılması her zaman derleyicinin tetiklenen derlemeyi tamamlamasını beklemekten daha uzun sürdü. Sıfıra yakın bekleme süreleriyle gerçekten anında tatmin oldu. Ve üretilen kodun kalitesi, o zamanlar mevcut olan en iyi derleyicilerle tamamen eşit olmasa da, çoğu görev için oldukça iyi ve genel olarak oldukça kabul edilebilirdi.


1
Bir Pascal / Modula-2 / Oberon / Oberon-2 derleyicisi, modern bir makinede bir saniyeden daha kısa sürede
derlenir

1
Alıntı eklendi, bkz. Referans [1].
Andreas

1
“... prensipler ... Go (Google), Swift (Apple) gibi modern dillere doğru yol bulma” Swift'in bu listeye nasıl girdiğinden emin değilim: Swift derleyicisi buzul . Yakın zamanda bir CocoaHeads Berlin buluşmasında, birisi orta büyüklükte bir çerçeve için bazı rakamlar sağladı, saniyede 16 LOC'a geldi.
mpw

13

Go hızlı olacak şekilde tasarlandı ve gösteriyor.

  1. Bağımlılık Yönetimi: başlık dosyası yok, sadece doğrudan içe aktarılan paketlere bakmanız gerekiyor (içe aktardıkları şey hakkında endişelenmenize gerek yok), böylece doğrusal bağımlılıklarınız var.
  2. Dilbilgisi: dilin dilbilgisi basittir, bu nedenle kolayca ayrıştırılır. Özelliklerin sayısı azalmasına rağmen, derleyici kodunun kendisi sıkıdır (birkaç yol).
  3. Aşırı yüke izin verilmez: bir sembol görürsünüz, hangi yönteme başvurduğunu bilirsiniz.
  4. Go'yu paralel olarak derlemek çok kolaydır, çünkü her paket bağımsız olarak derlenebilir.

GO'nun bu özelliklere sahip tek dil olmadığını unutmayın (modüller modern dillerdeki normdur), ancak iyi yaptılar.


(4) noktası tamamen doğru değildir. Birbirine bağımlı olan modüller, modüller arası satır içi ve eşyalar için bağımlılık sırasına göre derlenmelidir.
fuz

1
@FUZxxl: Bu sadece optimizasyon aşamasıyla ilgili olsa da, arka uç IR nesline kadar mükemmel paralelliğe sahip olabilirsiniz; bu nedenle sadece bağlantı aşamasında yapılabilen çapraz modül optimizasyonu söz konusudur ve bağlantı yine de paralel değildir. Tabii ki, çalışmanızı çoğaltmak istemiyorsanız (yeniden ayrıştırma), bir "kafes" şekilde derlemeniz daha iyidir: 1 / bağımlılığı olmayan modüller, sadece (1), 3 / modüllere bağlı olarak 2 / modüller sadece (1) ve (2) 'ye bağlı olarak, ...
Matthieu M.Mar

2
Bu Makefile gibi temel yardımcı programları kullanarak yapmak çok kolaydır.
fuz

12

Alan Donovan ve Brian Kernighan'ın " Git Programlama Dili " kitabından alıntılar:

Go derleme, sıfırdan inşa ederken bile diğer derlenmiş dillerden daha hızlıdır. Derleyicinin hızının üç ana nedeni vardır. İlk olarak, tüm içe aktarma işlemlerinin her kaynak dosyanın başında açıkça listelenmesi gerekir, bu nedenle derleyicinin bağımlılıklarını belirlemek için tüm dosyayı okuması ve işlemesi gerekmez. İkincisi, bir paketin bağımlılıkları yönlendirilmiş asiklik bir grafik oluşturur ve döngü olmadığından paketler ayrı ayrı ve belki de paralel olarak derlenebilir. Son olarak, derlenmiş bir Go paketinin nesne dosyası, verme bilgilerini yalnızca paketin kendisi için değil, bağımlılıkları için de kaydeder. Bir paketi derlerken, derleyici her içe aktarma için bir nesne dosyasını okumalı ancak bu dosyaların ötesine bakmalıdır.


9

Temel derleme fikri aslında çok basittir. Bir özyinelemeli iniş ayrıştırıcı, ilke olarak, G / Ç bağlı hızda çalışabilir. Kod üretimi temelde çok basit bir işlemdir. Bir sembol tablosu ve temel tip sistemi, çok fazla hesaplama gerektiren bir şey değildir.

Ancak, bir derleyiciyi yavaşlatmak zor değildir.

Çok seviyeli bir önişlemci faz, varsa dahil olan şeylerdir gibi aşağı yük zor değil, yararlı olarak direktifleri, makro tanımları ve koşullu derleme. (Bir örnek olarak, Windows ve MFC başlık dosyalarını düşünüyorum.) Bu yüzden önceden derlenmiş üstbilgiler gereklidir.

Oluşturulan kodun optimize edilmesi açısından, bu aşamaya ne kadar işlem eklenebileceğine dair bir sınır yoktur.


7

Basitçe (kendi kelimelerimle), çünkü sözdizimi çok kolaydır (analiz etmek ve ayrıştırmak)

Örneğin, hiçbir tür kalıtımı, yeni türün temel tür tarafından uygulanan kurallara uyup uymadığını öğrenmek için sorunlu analiz anlamına gelmez.

Örneğin bu kod örneğinde: "arayüzler" derleyici gitmez ve istenen türün o türü analiz ederken verilen arayüzü uygulayıp uygulamadığını kontrol eder . Sadece kullanılıncaya kadar (ve eğer kullanılırsa) kontrol yapılır.

Diğer bir örnek olarak, derleyici bir değişkeni bildirip bildirmediğinizi (veya bir dönüş değeri tutmanız gerekiyorsa ve istemiyorsanız)

Aşağıdakiler derlenmez:

package main
func main() {
    var a int 
    a = 0
}
notused.go:3: a declared and not used

Bu tür zorlamalar ve ilkeler ortaya çıkan kodu daha güvenli hale getirir ve derleyicinin programcının yapabileceği ek doğrulama işlemleri yapmak zorunda değildir.

Genel olarak, tüm bu ayrıntılar bir dilin ayrıştırılmasını kolaylaştırır ve bu da hızlı derlemeler sağlar.

Yine, kendi sözlerimle.


3

Bence Go derleyici yaratmaya paralel olarak tasarlandı, bu yüzden doğumdan en iyi arkadaşlardı. (IMO)


0
  • Go , tüm dosyalar için bağımlılıkları bir kez içe aktarır , böylece içe aktarma süresi proje boyutuyla katlanarak artmaz.
  • Daha basit dilbilim onları yorumlamak daha az bilgi gerektirir.

Başka?

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.