รวบรวมได้อย่างไรอย่างรวดเร็ว


217

ฉัน Googled และแหย่ไปที่เว็บไซต์ Go แต่ดูเหมือนว่าฉันจะไม่สามารถหาคำอธิบายสำหรับเวลาสร้างที่ไม่ธรรมดาของ Go พวกเขาเป็นผลิตภัณฑ์ของคุณสมบัติภาษา (หรือขาดมัน), คอมไพเลอร์เพิ่มประสิทธิภาพสูงหรืออย่างอื่น? ฉันไม่พยายามโปรโมตไป; ฉันแค่อยากรู้


12
@ สนับสนุนฉันตระหนักดีว่า ฉันคิดว่าการใช้คอมไพเลอร์ในลักษณะที่มันรวบรวมด้วยความรวดเร็วที่เห็นได้ชัดเจนคืออะไรนอกจากการเพิ่มประสิทธิภาพก่อนวัยอันควร ยิ่งไปกว่านั้นมันหมายถึงผลลัพธ์ของการออกแบบและพัฒนาซอฟต์แวร์ที่ดี นอกจากนี้ฉันไม่สามารถยืนดูคำพูดของ Knuth ที่นำออกจากบริบทและนำไปใช้อย่างไม่ถูกต้อง
Adam Crossland

55
คำถามของผู้มองโลกในแง่ร้ายของคำถามนี้คือ "ทำไม C ++ จึงคอมไพล์ช้ามาก?" stackoverflow.com/questions/588884/…
dan04

14
ฉันโหวตให้เปิดคำถามนี้อีกครั้งเนื่องจากไม่ใช่ความคิดเห็น หนึ่งสามารถให้ภาพรวมทางเทคนิคที่ดี (ไม่มีความเห็น) ของภาษาและ / หรือตัวเลือกคอมไพเลอร์ซึ่งความเร็วในการรวบรวมสิ่งอำนวยความสะดวก
Martin Tournoij

สำหรับโครงการขนาดเล็ก Go ดูเหมือนจะช้าสำหรับฉัน นี่เป็นเพราะฉันจำได้ว่า Turbo-Pascal นั้นเร็วกว่าคอมพิวเตอร์มากซึ่งอาจช้ากว่าหลายพันเท่า prog21.dadgum.com/47.html?repost=true ทุกครั้งที่ฉันพิมพ์ "go build" และไม่มีอะไรเกิดขึ้นเป็นเวลาหลายวินาทีฉันคิดว่ากลับไปใช้คอมไพเลอร์เก่าแก่ของ Fortran และการ์ดเจาะรู YMMV TLDR: "ช้า" และ "เร็ว" เป็นคำที่เกี่ยวข้อง
RedGrittyBrick

แนะนำให้อ่านแน่นอนdave.cheney.net/2014/06/07/five-things-that-make-go-fastสำหรับข้อมูลเชิงลึกที่ละเอียดยิ่งขึ้น
Karthik

คำตอบ:


193

การวิเคราะห์การพึ่งพา

ไปคำถามที่พบบ่อยที่ใช้จะมีประโยคต่อไปนี้:

Go เป็นแบบจำลองสำหรับการสร้างซอฟต์แวร์ที่ทำให้การวิเคราะห์การพึ่งพาง่ายและหลีกเลี่ยงค่าใช้จ่ายส่วนใหญ่ในรูปแบบ C รวมถึงไฟล์และไลบรารี

ในขณะที่วลีไม่ได้อยู่ในคำถามที่พบบ่อยอีกต่อไปแล้วหัวข้อนี้จะกล่าวถึงใน Talk Go at Googleซึ่งเปรียบเทียบวิธีการวิเคราะห์การพึ่งพาของ C / C ++ และ Go

นั่นคือเหตุผลหลักของการรวบรวมที่รวดเร็ว และนี่คือการออกแบบ


วลีนี้ไม่ได้อยู่ในคำถามที่พบบ่อยของ Go อีกต่อไป แต่มีคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับหัวข้อ "การวิเคราะห์การพึ่งพา" เปรียบเทียบ C / C ++ และวิธี Pascal / Modula / Go ที่มีอยู่ในการพูดคุยGo ที่ Google
rob74

76

ฉันคิดว่ามันไม่ได้ว่าคอมไพเลอร์ไปเป็นอย่างรวดเร็วก็ว่าคอมไพเลอร์อื่น ๆ จะช้า

คอมไพเลอร์ C และ C ++ ต้องแยกส่วนหัวจำนวนมหาศาล - ตัวอย่างเช่นการคอมไพล์ C ++ "hello world" ต้องมีการคอมไพล์โค้ด 18k บรรทัดซึ่งเกือบครึ่งเมกะไบต์ของแหล่งที่มา!

$ cpp hello.cpp | wc
  18364   40513  433334

คอมไพเลอร์ Java และ C # ทำงานใน VM ซึ่งหมายความว่าก่อนที่พวกเขาจะสามารถรวบรวมสิ่งใดระบบปฏิบัติการจะต้องโหลด VM ทั้งหมดจากนั้นพวกเขาจะต้องรวบรวม JIT จาก bytecode ไปเป็นรหัสเนทีฟซึ่งทั้งหมดใช้เวลาพอสมควร

ความเร็วในการรวบรวมขึ้นอยู่กับหลายปัจจัย

บางภาษาได้รับการออกแบบให้รวบรวมอย่างรวดเร็ว ตัวอย่างเช่น Pascal ได้รับการออกแบบให้คอมไพล์ด้วยคอมไพเลอร์ผ่านครั้งเดียว

คอมไพเลอร์เองก็สามารถปรับให้เหมาะสมเช่นกัน ตัวอย่างเช่นคอมไพเลอร์ Turbo Pascal ถูกเขียนในแอสเซมเบลอร์ที่ปรับปรุงด้วยมือซึ่งรวมกับการออกแบบภาษาส่งผลให้คอมไพเลอร์ที่ทำงานอย่างรวดเร็วจริงๆทำงานบนฮาร์ดแวร์ 286 ชั้น ฉันคิดว่าแม้ตอนนี้คอมไพเลอร์ Pascal สมัยใหม่ (เช่น FreePascal) จะเร็วกว่าคอมไพเลอร์ Go


19
คอมไพเลอร์ C # ของ Microsoft ไม่ได้ทำงานใน VM มันยังคงเขียนใน C ++ เป็นหลักสำหรับเหตุผลด้านประสิทธิภาพ
blucz

19
Turbo Pascal และรุ่นที่ใหม่กว่า Delphi เป็นตัวอย่างที่ดีที่สุดสำหรับคอมไพเลอร์ที่เร็วที่สุด หลังจากที่สถาปนิกของทั้งคู่ย้ายไปที่ Microsoft เราได้เห็นการปรับปรุงอย่างมากมายทั้งในโปรแกรมแปลภาษา MS และภาษา นั่นไม่ใช่เรื่องบังเอิญแบบสุ่ม
TheBlastOne

7
บรรทัด 18k (18364 เป็นรหัสที่แน่นอน) คือ 433334 ไบต์ (~ 0,5MB)
el.pescado

9
คอมไพเลอร์ C # ได้รับการคอมไพล์ด้วย C # ตั้งแต่ปี 2011 เพียงอัปเดตในกรณีที่ทุกคนอ่านได้ในภายหลัง
Kurt Koller

3
คอมไพเลอร์ C # และ CLR ที่รัน MSIL ที่สร้างขึ้นเป็นสิ่งที่ต่างออกไป ฉันค่อนข้างแน่ใจว่า CLR ไม่ได้เขียนใน C #
jocull

39

มีหลายสาเหตุที่ทำให้คอมไพเลอร์ Go เร็วกว่าคอมไพเลอร์ C / C ++ ส่วนใหญ่:

  • เหตุผลหลัก : คอมไพเลอร์ C / C ++ ส่วนใหญ่มีการออกแบบที่ไม่ดีเป็นพิเศษ (จากมุมมองความเร็วในการรวบรวม) นอกจากนี้จากมุมมองความเร็วการรวบรวมบางส่วนของระบบนิเวศ C / C ++ (เช่นบรรณาธิการที่โปรแกรมเมอร์เขียนโค้ด) ไม่ได้รับการออกแบบโดยคำนึงถึงความเร็วในการรวบรวม

  • เหตุผลด้านบน : ความเร็วในการรวบรวมที่รวดเร็วเป็นตัวเลือกที่ใส่ใจในคอมไพเลอร์ Go และในภาษา Go

  • คอมไพเลอร์ Go มีเครื่องมือเพิ่มประสิทธิภาพที่ง่ายกว่าคอมไพเลอร์ C / C ++

  • ต่างจาก C ++, Go ไม่มีเทมเพลตและไม่มีฟังก์ชั่นอินไลน์ ซึ่งหมายความว่า Go ไม่จำเป็นต้องดำเนินการใด ๆ กับอินสแตนซ์ของแม่แบบหรือฟังก์ชัน

  • คอมไพเลอร์ Go สร้างรหัสแอสเซมบลีระดับต่ำในไม่ช้าและเครื่องมือเพิ่มประสิทธิภาพทำงานกับแอสเซมบลีโค้ดในขณะที่คอมไพเลอร์ C / C ++ ทั่วไปการเพิ่มประสิทธิภาพผ่านการทำงานในการเป็นตัวแทนภายในของรหัสต้นฉบับดั้งเดิม โอเวอร์เฮดพิเศษในคอมไพเลอร์ C / C ++ มาจากข้อเท็จจริงที่ว่าจำเป็นต้องสร้างการแสดงภายใน

  • การลิงก์ขั้นสุดท้าย (5l / 6l / 8l) ของโปรแกรม Go อาจช้ากว่าการลิงก์โปรแกรม C / C ++ เนื่องจากคอมไพเลอร์ Go กำลังดำเนินการผ่านแอสเซมบลีรหัสที่ใช้ทั้งหมดและอาจเป็นการกระทำพิเศษอื่น ๆ ที่ C / C ++ ลิงเกอร์ไม่ทำงาน

  • คอมไพเลอร์ C / C ++ บางตัว (GCC) สร้างคำแนะนำในรูปแบบข้อความ (จะถูกส่งผ่านไปยังแอสเซมเบลอร์) ในขณะที่คอมไพเลอร์ Go สร้างคำแนะนำในรูปแบบไบนารี ต้องทำงานพิเศษ (แต่ไม่มาก) เพื่อที่จะแปลงข้อความเป็นไบนารี

  • คอมไพเลอร์ Go กำหนดเป้าหมายเฉพาะสถาปัตยกรรมซีพียูจำนวนน้อยในขณะที่คอมไพเลอร์ GCC มีเป้าหมายเป็นซีพียูจำนวนมาก

  • คอมไพเลอร์ที่ออกแบบโดยมีเป้าหมายในการรวบรวมความเร็วสูงเช่น Jikes นั้นรวดเร็ว สำหรับซีพียู 2GHz Jikes สามารถคอมไพล์โค้ด Java ได้ 20,000 บรรทัดต่อวินาที (และโหมดการรวบรวมที่เพิ่มขึ้นนั้นมีประสิทธิภาพมากกว่า)


17
คอมไพเลอร์ของ Go inlines ฟังก์ชั่นขนาดเล็ก ฉันไม่แน่ใจว่าการกำหนดเป้าหมายของ CPU จำนวนน้อยจะทำให้คุณทำงานช้าลงได้อย่างไร ... ฉันคิดว่า gcc ไม่ได้สร้างรหัส PPC ในขณะที่ฉันรวบรวม x86
Brad Fitzpatrick

@BradFitzpatrick เกลียดที่จะรื้อฟื้นความคิดเห็นเก่า แต่ด้วยการกำหนดเป้าหมายจำนวนผู้พัฒนาแพลตฟอร์มขนาดเล็กของคอมไพเลอร์สามารถใช้เวลาในการปรับให้เหมาะสมสำหรับแต่ละข้อ
ความคงทน

การใช้แบบฟอร์มกลางช่วยให้คุณสามารถสนับสนุนสถาปัตยกรรมได้มากขึ้นตั้งแต่ตอนนี้คุณเพียง แต่ต้องเขียนแบ็กเอนด์ใหม่สำหรับสถาปัตยกรรมใหม่แต่ละแห่ง
phuclv

34

ประสิทธิภาพการรวบรวมเป็นเป้าหมายการออกแบบที่สำคัญ:

ในที่สุดมันก็ตั้งใจว่าจะเร็ว: ควรใช้เวลาไม่กี่วินาทีในการสร้างไฟล์ปฏิบัติการขนาดใหญ่บนคอมพิวเตอร์เครื่องเดียว เพื่อให้บรรลุเป้าหมายเหล่านี้จำเป็นต้องมีการจัดการกับปัญหาทางภาษาหลายประการ: ระบบการพิมพ์ที่แสดงออก แต่มีน้ำหนักเบา; การเกิดขึ้นพร้อมกันและการเก็บขยะ ข้อมูลจำเพาะการพึ่งพาที่เข้มงวด และอื่น ๆ คำถามที่พบบ่อย

คำถามที่พบบ่อยเกี่ยวกับภาษานั้นค่อนข้างน่าสนใจเกี่ยวกับคุณสมบัติภาษาเฉพาะที่เกี่ยวข้องกับการวิเคราะห์คำ:

ประการที่สองภาษาได้รับการออกแบบให้ง่ายต่อการวิเคราะห์และสามารถแยกวิเคราะห์ได้โดยไม่มีตารางสัญลักษณ์


6
ที่ไม่เป็นความจริง. คุณไม่สามารถแยกวิเคราะห์ซอร์สโค้ดของ Go ได้อย่างสมบูรณ์โดยไม่มีตารางสัญลักษณ์

12
ฉันยังไม่เห็นว่าทำไมการรวบรวมขยะจึงช่วยเพิ่มเวลาในการรวบรวม มันแค่ทำไม่ได้
TheBlastOne

3
นี่เป็นคำพูดจากคำถามที่พบบ่อย: golang.org/doc/go_faq.htmlฉันไม่สามารถพูดได้ว่าพวกเขาล้มเหลวในการบรรลุเป้าหมาย (ตารางสัญลักษณ์) หรือตรรกะของพวกเขาผิดปกติ (GC)
Larry OBrien

5
@FUZxxl ไปที่golang.org/ref/spec#Primary_expressionsและพิจารณาทั้งสองซีเควนซ์ [ตัวถูกดำเนินการ, โทร] และ [การแปลง] ตัวอย่างซอร์สโค้ด Go: identifier1 (identifier2) หากไม่มีตารางสัญลักษณ์จะไม่สามารถตัดสินใจได้ว่าตัวอย่างนี้เป็นการโทรหรือการแปลง | ภาษาใด ๆ สามารถแยกวิเคราะห์ได้บ้างโดยไม่มีตารางสัญลักษณ์ มันเป็นความจริงที่ส่วนใหญ่ของซอร์สโค้ด Go สามารถแยกวิเคราะห์ได้โดยไม่มีตารางสัญลักษณ์ แต่มันไม่เป็นความจริงที่เป็นไปได้ที่จะรับรู้องค์ประกอบไวยากรณ์ทั้งหมดที่กำหนดไว้ในข้อมูลจำเพาะของ golang

3
@Atom คุณทำงานอย่างหนักเพื่อป้องกันโปรแกรมแยกวิเคราะห์เป็นส่วนหนึ่งของรหัสที่รายงานข้อผิดพลาด ตัวแยกวิเคราะห์โดยทั่วไปทำงานได้ไม่ดีในการรายงานข้อความแสดงข้อผิดพลาดที่สอดคล้องกัน ที่นี่คุณสร้างแผนภูมิการแยกวิเคราะห์สำหรับนิพจน์ราวกับaTypeเป็นการอ้างอิงตัวแปรและต่อมาในช่วงการวิเคราะห์เชิงความหมายเมื่อคุณพบว่าไม่ใช่คุณพิมพ์ข้อผิดพลาดที่มีความหมายในเวลานั้น
Sam Harwell

26

ในขณะที่ส่วนใหญ่ข้างต้นเป็นจริงมีจุดสำคัญอย่างหนึ่งที่ไม่ได้กล่าวถึงจริงๆ: การจัดการการพึ่งพา

ไปจะต้องรวมถึงแพคเกจที่คุณกำลังนำเข้าโดยตรง (เช่นที่นำเข้าแล้วสิ่งที่พวกเขาต้องการ) นี่คือความแตกต่างอย่างสิ้นเชิงกับ C / C ++ ที่ทุกไฟล์เดียวเริ่มรวมถึงส่วนหัว x ซึ่งรวมถึงส่วนหัว y ฯลฯ ด้านล่างบรรทัด: การรวบรวมของ Go ใช้เวลาเชิงเส้น wrt จำนวนแพคเกจที่นำเข้าที่ C / C ++ ใช้เวลาชี้แจง


22

การทดสอบที่ดีสำหรับประสิทธิภาพการแปลของคอมไพเลอร์คือการรวบรวมตนเอง: ใช้เวลานานแค่ไหนที่คอมไพเลอร์ที่ได้รับจะรวบรวมตัวเอง? สำหรับ C ++ ต้องใช้เวลานาน (ชั่วโมง?) โดยการเปรียบเทียบคอมไพเลอร์ Pascal / Modula-2 / Oberon จะรวบรวมตัวเองในเวลาน้อยกว่าหนึ่งวินาทีในเครื่องจักรที่ทันสมัย ​​[1]

Go ได้รับแรงบันดาลใจจากภาษาเหล่านี้ แต่เหตุผลสำคัญบางประการสำหรับประสิทธิภาพนี้ ได้แก่ :

  1. ไวยากรณ์ที่กำหนดไว้อย่างชัดเจนที่มีเสียงทางคณิตศาสตร์สำหรับการสแกนและการแยกวิเคราะห์ที่มีประสิทธิภาพ

  2. ภาษาชนิดปลอดภัยและแบบคงที่รวบรวมที่ใช้แยกต่างหากสะสมที่มีการพึ่งพาและประเภทของการตรวจสอบข้ามเขตแดนโมดูลเพื่อหลีกเลี่ยงการที่ไม่จำเป็นอีกครั้งอ่านไฟล์ส่วนหัวและอีกรวบรวมของโมดูลอื่น ๆ - เมื่อเทียบกับอิสระสะสมเหมือนใน C / C ++ ที่ ไม่มีการตรวจสอบข้ามโมดูลดังกล่าวโดยคอมไพเลอร์ (ดังนั้นจึงจำเป็นต้องอ่านไฟล์ส่วนหัวทั้งหมดซ้ำแล้วซ้ำอีกแม้จะเป็นโปรแกรม "Hello world" แบบบรรทัดเดียวอย่างง่าย)

  3. การใช้งานคอมไพเลอร์ที่มีประสิทธิภาพ (เช่น single-pass, การแยกวิเคราะห์จากบนลงล่างแบบเรียกซ้ำ) - ซึ่งแน่นอนว่าได้รับการช่วยเหลืออย่างมากจากคะแนน 1 และ 2 ข้างต้น

หลักการเหล่านี้ได้รับการยอมรับและนำมาใช้อย่างเต็มที่ในปี 1970 และ 1980 ในภาษาต่างๆเช่น Mesa, Ada, Modula-2 / Oberon และอีกหลายคนและตอนนี้ (ในปี 2010) หาทางเป็นภาษาสมัยใหม่เช่น Go (Google) , Swift (Apple), C # (Microsoft) และอื่น ๆ อีกมากมาย

หวังว่าเร็ว ๆ นี้จะเป็นบรรทัดฐานและไม่ใช่ข้อยกเว้น ในการไปถึงที่นั่นต้องมีสองสิ่ง:

  1. อันดับแรกผู้ให้บริการแพลตฟอร์มซอฟต์แวร์เช่น Google, Microsoft และ Apple ควรเริ่มต้นด้วยการสนับสนุนให้นักพัฒนาแอปพลิเคชันใช้วิธีการรวบรวมใหม่ในขณะที่ทำให้พวกเขาสามารถใช้ฐานรหัสที่มีอยู่อีกครั้งได้ นี่คือสิ่งที่ Apple พยายามทำกับภาษาการเขียนโปรแกรม Swift ซึ่งสามารถอยู่ร่วมกับ Objective-C (เนื่องจากใช้สภาพแวดล้อมรันไทม์เดียวกัน)

  2. ประการที่สองแพลตฟอร์มซอฟต์แวร์พื้นฐานควรถูกเขียนซ้ำอีกครั้งเมื่อเวลาผ่านไปโดยใช้หลักการเหล่านี้ในขณะเดียวกันก็ออกแบบลำดับชั้นของโมดูลในกระบวนการพร้อมกันเพื่อทำให้พวกมันมีเสาหินน้อยลง แน่นอนว่านี่เป็นงานช้างแมมมอ ธ และอาจใช้เวลาส่วนหนึ่งในทศวรรษที่ดีกว่านี้ (หากพวกเขากล้าพอที่จะทำมันได้จริง - ซึ่งฉันไม่แน่ใจในกรณีของ Google)

ไม่ว่าในกรณีใดมันเป็นแพลตฟอร์มที่ขับเคลื่อนการยอมรับภาษาไม่ใช่วิธีอื่น

อ้างอิง:

[1] http://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.System.pdfหน้า 6: "คอมไพเลอร์รวบรวมตัวเองในเวลาประมาณ 3 วินาที" คำพูดนี้ใช้สำหรับบอร์ดพัฒนา FPGA Xilinx Spartan-3 ต้นทุนต่ำที่ทำงานที่ความถี่สัญญาณนาฬิกา 25 MHz และมีหน่วยความจำหลัก 1 MByte จากสิ่งนี้สามารถคาดการณ์ได้ง่ายถึง "น้อยกว่า 1 วินาที" สำหรับโปรเซสเซอร์ที่ทันสมัยที่ทำงานที่ความถี่สัญญาณนาฬิกาที่สูงกว่า 1 GHz และหน่วยความจำหลักหลาย GBytes (เช่นคำสั่งขนาดใหญ่หลายอันทรงพลัง แม้ว่าจะคำนึงถึงความเร็ว I / O แล้วก็ตาม ย้อนกลับไปในปี 1990 เมื่อ Oberon ทำงานบนโปรเซสเซอร์ 25MHz NS32X32 พร้อมหน่วยความจำหลัก 2-4 เมกะไบต์คอมไพเลอร์รวบรวมตัวเองในเวลาเพียงไม่กี่วินาที แนวคิดของการรอคอยจริงสำหรับคอมไพเลอร์ที่จะเสร็จสิ้นรอบการรวบรวมนั้นโปรแกรมเมอร์ของ Oberon ไม่รู้จักเลยแม้แต่ตอนนั้น สำหรับโปรแกรมทั่วไปก็มักจะใช้เวลามากขึ้นในการลบนิ้วออกจากปุ่มเมาส์ที่เรียกใช้คำสั่งการคอมไพล์กว่ารอให้คอมไพเลอร์ทำการคอมไพล์ให้เสร็จสมบูรณ์ มันเป็นเรื่องน่ายินดีอย่างแท้จริงด้วยเวลารอเกือบเป็นศูนย์ และคุณภาพของรหัสที่ผลิตแม้ว่าจะไม่เสมอไปอย่างสมบูรณ์กับคอมไพเลอร์ที่ดีที่สุดที่มีอยู่ในตอนนั้นก็ดีมากสำหรับงานส่วนใหญ่และเป็นที่ยอมรับโดยทั่วไป


1
Pascal / Modula-2 / Oberon / Oberon-2 คอมไพเลอร์จะรวบรวมตัวเองในเวลาน้อยกว่าหนึ่งวินาทีบนเครื่องที่ทันสมัย [อ้างจำเป็น]
CoffeeandCode

1
เพิ่มการอ้างอิงแล้วดูการอ้างอิง [1]
Andreas

1
"... หลักการ ... หาทางลงในภาษาที่ทันสมัยเช่น Go (Google) สวิฟท์ (แอปเปิ้ล)" ไม่แน่ใจว่าสวิฟท์ที่ทำลงในรายการว่าคอมไพเลอร์สวิฟท์เป็นน้ำแข็ง ในการพบปะกันครั้งล่าสุดของ CocoaHeads Berlin มีคนให้ตัวเลขจำนวนหนึ่งสำหรับกรอบงานขนาดกลางพวกเขามาที่ 16 LOC ต่อวินาที
mpw

13

ไปถูกออกแบบมาให้รวดเร็วและมันแสดงให้เห็น

  1. การจัดการการพึ่งพา: ไม่มีไฟล์ส่วนหัวคุณเพียงแค่ต้องดูแพ็คเกจที่นำเข้าโดยตรง (ไม่ต้องกังวลเกี่ยวกับสิ่งที่พวกเขานำเข้า) ดังนั้นคุณจึงมีการอ้างอิงเชิงเส้น
  2. ไวยากรณ์: ไวยากรณ์ของภาษานั้นเรียบง่ายจึงแยกวิเคราะห์ได้ง่าย แม้ว่าจำนวนของคุณสมบัติจะลดลงดังนั้นรหัสคอมไพเลอร์เองก็แน่น (ไม่กี่เส้นทาง)
  3. ไม่อนุญาตให้ใช้งานเกินพิกัด: คุณเห็นสัญลักษณ์คุณรู้วิธีที่ใช้อ้างอิง
  4. เป็นไปได้เล็กน้อยที่จะคอมไพล์ Go แบบขนานเนื่องจากแต่ละแพ็คเกจสามารถรวบรวมได้อย่างอิสระ

โปรดทราบว่า GO ไม่ใช่ภาษาเดียวที่มีคุณสมบัติดังกล่าว (โมดูลเป็นบรรทัดฐานในภาษาสมัยใหม่) แต่ทำได้ดี


คะแนน (4) ไม่เป็นความจริงทั้งหมด โมดูลที่ขึ้นอยู่กับแต่ละอื่น ๆ ควรจะรวบรวมในลำดับของการพึ่งพาเพื่อให้การอินไลน์โมดูลข้ามและสิ่ง
fuz

1
@FUZxxl: สิ่งนี้เกี่ยวข้องกับขั้นตอนการปรับให้เหมาะสมเท่านั้น แต่คุณสามารถมีความเท่าเทียมกันอย่างสมบูรณ์แบบจนถึงรุ่น IR แบ็กเอนด์ ดังนั้นจึงควรคำนึงถึงการเพิ่มประสิทธิภาพข้ามโมดูลเท่านั้นซึ่งสามารถทำได้ในระยะลิงก์และลิงก์จะไม่ขนานกันอยู่แล้ว แน่นอนถ้าคุณไม่ต้องการทำซ้ำงานของคุณ (การวิเคราะห์คำซ้ำ) คุณควรรวบรวมข้อมูลด้วยวิธี "ขัดแตะ": 1 / โมดูลโดยไม่มีการพึ่งพา 2 / โมดูลขึ้นอยู่กับ (1), 3 / โมดูล ขึ้นอยู่กับ (1) และ (2), ...
Matthieu M.

2
ซึ่งเป็นเรื่องง่ายที่จะทำโดยใช้ยูทิลิตี้พื้นฐานเช่น Makefile
fuz

12

ข้อความจากหนังสือ " The Go Programming Language " โดย Alan Donovan และ Brian Kernighan:

การรวบรวมข้อมูลเป็นไปอย่างรวดเร็วกว่าภาษาที่รวบรวมโดยส่วนใหญ่แม้จะสร้างจากขั้นตอนแรก มีสามเหตุผลหลักสำหรับความเร็วของคอมไพเลอร์ ขั้นแรกการนำเข้าทั้งหมดจะต้องมีการระบุไว้อย่างชัดเจนที่จุดเริ่มต้นของแต่ละไฟล์ต้นฉบับดังนั้นคอมไพเลอร์ไม่จำเป็นต้องอ่านและประมวลผลไฟล์ทั้งหมดเพื่อตรวจสอบการอ้างอิง ประการที่สองการพึ่งพาของแพ็กเกจจะสร้างกราฟ acyclic โดยตรงและเนื่องจากไม่มีวัฏจักรจึงสามารถรวบรวมแพ็กเกจแยกต่างหากและอาจขนานกัน สุดท้ายไฟล์อ็อบเจ็กต์สำหรับแพ็กเกจ Go ที่รวบรวมจะบันทึกข้อมูลการส่งออกไม่เพียง แต่สำหรับแพ็กเกจเท่านั้น แต่สำหรับการอ้างอิงด้วย เมื่อรวบรวมแพคเกจคอมไพเลอร์จะต้องอ่านหนึ่งอ็อบเจ็กต์ไฟล์สำหรับแต่ละการอิมพอร์ต แต่ไม่จำเป็นต้องดูเกินกว่าไฟล์เหล่านี้


9

แนวคิดพื้นฐานของการรวบรวมนั้นง่ายมาก โดยหลักการแล้วตัวแยกวิเคราะห์แบบวนซ้ำสามารถเรียกใช้ที่ I / O ความเร็วที่ถูกผูกไว้ การสร้างรหัสนั้นเป็นกระบวนการที่ง่ายมาก ตารางสัญลักษณ์และระบบชนิดพื้นฐานไม่ใช่สิ่งที่ต้องใช้การคำนวณจำนวนมาก

อย่างไรก็ตามมันไม่ได้ยากที่จะชะลอตัวแปล

หากมีขั้นตอนตัวประมวลผลล่วงหน้าที่มีหลายระดับจะมีคำสั่งคำจำกัดความของแมโครและการคอมไพล์ตามเงื่อนไขซึ่งมีประโยชน์เหมือนกับสิ่งเหล่านั้นมันไม่ยากที่จะโหลดลง (ตัวอย่างหนึ่งฉันคิดว่าไฟล์ส่วนหัวของ Windows และ MFC) นั่นเป็นเหตุผลว่าทำไมส่วนหัว precompiled จึงมีความจำเป็น

ในแง่ของการปรับรหัสที่สร้างให้เหมาะสมไม่มีการ จำกัด จำนวนการประมวลผลที่สามารถเพิ่มลงในเฟสนั้นได้


7

เพียงแค่ (ในคำพูดของฉันเอง) เพราะไวยากรณ์เป็นเรื่องง่ายมาก (ในการวิเคราะห์และแยกวิเคราะห์)

ตัวอย่างเช่นไม่มีการสืบทอดประเภทหมายความว่าไม่ใช่การวิเคราะห์ที่มีปัญหาเพื่อดูว่าประเภทใหม่เป็นไปตามกฎที่กำหนดโดยประเภทฐานหรือไม่

ตัวอย่างเช่นในตัวอย่างรหัสนี้: "interfaces"คอมไพเลอร์จะไม่ไปและตรวจสอบว่าประเภทที่ต้องการใช้อินเตอร์เฟสที่กำหนดในขณะที่วิเคราะห์ประเภทนั้นหรือไม่ จนกว่าจะมีการใช้ (และหากมีการใช้) จะมีการตรวจสอบ

ตัวอย่างอื่น ๆ คอมไพเลอร์จะบอกคุณว่าคุณกำลังประกาศตัวแปรและไม่ได้ใช้มันหรือไม่ (หรือถ้าคุณควรจะเก็บค่าตอบแทนไว้และคุณไม่ได้ใช้)

ต่อไปนี้ไม่ได้รวบรวม:

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

การบังคับใช้และหลักการประเภทนี้ทำให้รหัสปลอดภัยขึ้นและคอมไพเลอร์ไม่จำเป็นต้องทำการตรวจสอบเพิ่มเติมที่โปรแกรมเมอร์สามารถทำได้

รายละเอียดทั้งหมดเหล่านี้ทำให้ภาษาสามารถแยกวิเคราะห์ได้ง่ายขึ้นซึ่งทำให้มีการรวบรวมอย่างรวดเร็ว

อีกครั้งในคำพูดของฉัน


3

ฉันคิดว่าโกได้รับการออกแบบควบคู่ไปกับการสร้างคอมไพเลอร์ดังนั้นพวกเขาจึงเป็นเพื่อนที่ดีที่สุดตั้งแต่แรกเกิด (IMO)


0
  • ไปพึ่งพาการนำเข้าหนึ่งครั้งสำหรับไฟล์ทั้งหมดดังนั้นเวลานำเข้าจะไม่เพิ่มขึ้นตามขนาดโครงการ
  • ภาษาศาสตร์ที่เรียบง่ายหมายถึงการตีความพวกเขาใช้คอมพิวเตอร์น้อยลง

มีอะไรอีกบ้าง?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.