คอมไพเลอร์ใช้ประโยชน์จากมัลติเธรดเพื่อการรวบรวมที่เร็วขึ้นหรือไม่?


16

ถ้าฉันจำหลักสูตรคอมไพเลอร์ของฉันได้อย่างถูกต้องคอมไพเลอร์ทั่วไปมีโครงร่างที่เรียบง่ายดังต่อไปนี้:

  • ตัววิเคราะห์คำจะสแกน (หรือเรียกใช้ฟังก์ชั่นการสแกนบางอย่าง) โค้ดต้นฉบับแบบตัวอักษรต่ออักขระ
  • สตริงของอักขระอินพุตถูกตรวจสอบกับพจนานุกรมของ lexemes เพื่อความถูกต้อง
  • หาก lexeme นั้นถูกต้องมันจะถูกจัดประเภทเป็นโทเค็นที่สอดคล้องกับมัน
  • parser ตรวจสอบความถูกต้องของการรวมกันของโทเค็น; token โดยโทเค็น

มันเป็นไปได้ในทางทฤษฎีหรือไม่ที่จะแบ่งซอร์สโค้ดออกเป็นควอเตอร์ คอมไพเลอร์มีตัวที่ใช้มัลติเธรดหรือไม่?




1
@RobertHarvey คำตอบแรกของลิงก์แรกเขียนไว้ว่า "แต่คอมไพเลอร์เองก็ยังคงเป็นเธรดเดี่ยว" นั่นคือไม่
8protons

ฉันแนะนำให้คุณอ่านคำตอบที่เหลือโดยเฉพาะลิงก์นี้และลิงค์ที่สองที่ฉันโพสต์ไว้
Robert Harvey

2
@RobertHarvey ลิงก์ที่สองที่คุณโพสต์จากความเข้าใจในสิ่งที่พูดมันกำลังพูดถึงคอมไพเลอร์ที่สร้างแอพพลิเคชั่นที่คอมไพล์ของคุณในเวอร์ชั่นมัลติเธรด มันไม่เกี่ยวกับคอมไพเลอร์เอง ขอบคุณสำหรับแหล่งข้อมูลที่คุณแบ่งปันและสละเวลาในการตอบกลับ
8protons

คำตอบ:


29

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

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

  • คุณไม่สามารถแยกอินพุตให้เป็นชิ้น ๆ หลาย ๆ อันและแยกพวกมันออกเป็นอิสระ สำหรับความเรียบง่ายคุณต้องการแยกขอบเขต lexme (เพื่อไม่ให้เธรดเริ่มทำงานในช่วงกลางของ lexme) แต่การกำหนดขอบเขต lexme อาจต้องใช้บริบทจำนวนมาก ตัวอย่างเช่นเมื่อคุณข้ามไปที่กลางไฟล์คุณต้องตรวจสอบให้แน่ใจว่าคุณไม่ได้กระโดดเป็นตัวอักษรสตริง แต่เพื่อตรวจสอบเรื่องนี้คุณต้องดูโดยทั่วไปว่าตัวละครทุกตัวที่มาก่อนซึ่งเกือบจะใช้งานได้มากเท่ากับเริ่มต้นด้วย นอกจากนี้ lexing มักจะเป็นคอขวดในคอมไพเลอร์สำหรับภาษาสมัยใหม่
  • การแยกคำนั้นยิ่งยากที่จะทำให้ขนานกัน ปัญหาทั้งหมดของการแยกข้อความที่ป้อนสำหรับ lexing ใช้มากขึ้นในการแยกโทเค็นสำหรับการแยก --- เช่นการกำหนดที่ฟังก์ชั่นเริ่มต้นเป็นเรื่องยากพอ ๆ กับการแยกเนื้อหาของฟังก์ชั่นที่จะเริ่มต้นด้วย ในขณะที่อาจมีวิธีการรอบ ๆ พวกเขาอาจจะซับซ้อนอย่างไม่เป็นสัดส่วนเพื่อประโยชน์เล็กน้อย การแยกวิเคราะห์ก็ไม่ได้เป็นคอขวดที่ใหญ่ที่สุด
  • หลังจากที่คุณแยกวิเคราะห์แล้วคุณจะต้องทำการแก้ไขชื่อ แต่สิ่งนี้นำไปสู่ความสัมพันธ์ที่แน่นแฟ้น เมื่อต้องการแก้ไขวิธีการเรียกที่นี่คุณอาจจะต้องแก้ปัญหาการนำเข้าครั้งแรกในโมดูลนี้ แต่ผู้ที่จำเป็นต้องมีการแก้ไขชื่อในอีกรวบรวมหน่วย ฯลฯ เดียวกันสำหรับอนุมานชนิดถ้าภาษาของคุณมีว่า

หลังจากนี้มันจะง่ายขึ้นเล็กน้อย การตรวจสอบชนิดและการปรับให้เหมาะสมและการสร้างรหัสอาจโดยหลักการแล้วจะถูกขนานกันที่ฟังก์ชันย่อย ฉันยังรู้ไม่กี่ว่าคอมไพเลอร์ใดที่ทำสิ่งนี้อาจเป็นเพราะการทำงานขนาดใหญ่นี้พร้อมกันค่อนข้างท้าทาย คุณต้องพิจารณาด้วยว่าโครงการซอฟต์แวร์ขนาดใหญ่ส่วนใหญ่มีหน่วยการคอมไพล์จำนวนมากที่วิธี "รันคอมไพเลอร์หลายชุดพร้อมกัน" นั้นเพียงพอที่จะทำให้คอร์ทั้งหมดของคุณมีการใช้งาน (และในบางกรณีแม้แต่ฟาร์มเซิร์ฟเวอร์ทั้งหมด) นอกจากนี้ในงานรวบรวมขนาดใหญ่ดิสก์ I / O สามารถเป็นคอขวดได้มากเท่ากับการรวบรวมงานจริง

จากทั้งหมดที่กล่าวมาฉันรู้คอมไพเลอร์ที่ทำให้การสร้างโค้ดและการปรับให้เหมาะสมนั้นขนานกัน คอมไพเลอร์ Rust สามารถแยกงานแบ็คเอนด์ (LLVM ซึ่งรวมถึงการปรับแต่งโค้ดที่ใช้กันทั่วไปว่าเป็น "มิดเอนด์") ในหลาย ๆ เธรด สิ่งนี้เรียกว่า "หน่วยโค้ด - เจน" ตรงกันข้ามกับความเป็นไปได้ในการขนานอื่น ๆ ที่กล่าวถึงข้างต้นสิ่งนี้ประหยัดเนื่องจาก:

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

2

การรวบรวมเป็นปัญหา "ขนานที่น่าอับอาย"

ไม่มีใครสนใจเวลารวบรวมไฟล์หนึ่งไฟล์ ผู้คนใส่ใจเวลารวบรวมไฟล์ 1,000 ไฟล์ และสำหรับไฟล์ 1,000 ไฟล์แต่ละคอร์ของโปรเซสเซอร์สามารถรวบรวมไฟล์ได้ครั้งละหนึ่งไฟล์ทำให้แกนประมวลผลทั้งหมดไม่ว่าง

เคล็ดลับ: "make" ใช้หลายแกนหากคุณให้ตัวเลือกบรรทัดคำสั่งที่ถูกต้อง หากปราศจากว่ามันจะรวบรวมไฟล์หนึ่งไฟล์หลังจากไฟล์อื่นบนระบบ 16 คอร์ ซึ่งหมายความว่าคุณสามารถรวบรวมได้เร็วขึ้น 16 เท่าด้วยการเปลี่ยนหนึ่งบรรทัดเป็นตัวเลือกการสร้างของคุณ

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