เปรียบเทียบเวลาในการคอมไพล์ของ Rust และ C++
(quick-lint-js.com)ได้ไปอ่านบทความน่าสนใจจากที่อื่นมาเลยอยากนำมาแนะนำ
Rust และ C++ มักถูกนำมาเปรียบเทียบกันในหลายด้าน อย่างไรก็ตาม การจะเปรียบเทียบเวลาในการคอมไพล์โดยตรงนั้นทำได้ยาก เพราะไม่ค่อยมีโปรเจ็กต์เดียวกันที่เขียนด้วยทั้งสองภาษา quick-lint-js ระบุว่าได้รีไรต์บางส่วนของโปรเจ็กต์ที่เขียนด้วย C++ ไปเป็น Rust เพื่อเปรียบเทียบเวลาในการคอมไพล์ แต่สภาพแวดล้อมการคอมไพล์นี้ไม่ได้รวม Windows
เกณฑ์ในการพอร์ต
- ไม่นับไลบรารีของบุคคลที่สาม
- ทำงานบน Linux และ macOS
- มี test suite ขนาดใหญ่
- FFI, พอยน์เตอร์, คอนเทนเนอร์มาตรฐานและที่เขียนขึ้นเอง, คลาสและฟังก์ชันยูทิลิตี, I/O, การทำงานพร้อมกัน, เจเนอริก, แมโคร, SIMD, การสืบทอด, ...
ข้อสรุป
- เวลาในการคอมไพล์ของ Rust ใกล้เคียงหรือช้ากว่า C++ (อย่างน้อยในโปรเจ็กต์นี้)
- Rust ต้องเขียนโค้ดมากกว่า C++
- ในการบิลด์แบบเต็ม (Full) C++ ใกล้เคียงหรือเร็วกว่า
- ในการบิลด์แบบเพิ่มเฉพาะส่วน (Incremental) บางครั้งสั้นกว่า บางครั้งยาวกว่า (และบางครั้งยาวมาก)
- ตัดสินใจว่าจะไม่พอร์ตส่วนที่เหลือของ quick-lint-js ไปเป็น Rust (แต่อาจทำถ้าช่วยให้เวลาบิลด์ดีขึ้น?)
4 ความคิดเห็น
ในประเทศเราก็มีคนใช้ Rust กันเยอะเหมือนกันนะครับ/ค่ะ อยากรู้ว่าทุกคนทำงานอยู่ในอุตสาหกรรมไหนกันบ้าง
หลังจากคอมไพล์ครั้งแรก ถ้าแก้ไขไฟล์
.cppเดี่ยว ๆ ที่ไม่ใช่ไฟล์hซึ่งมี dependency จำนวนมาก ฝั่ง C++ จะคอมไพล์ได้เร็วมาก เลยสงสัยว่า Rust เป็นอย่างไรบ้างเห็นว่ามีอธิบายเรื่องนี้ไว้อย่างละเอียดในส่วนคำถามที่พบบ่อยของเอกสาร Rust เลยเอามาแชร์ครับ
====================================
เหมือนว่า Rust จะคอมไพล์ช้า ทำไมถึงเป็นแบบนั้น?
เพราะต้องแปลโค้ดเป็นภาษาเครื่องและทำการปรับแต่งประสิทธิภาพ Rust มอบนามธรรมระดับสูงที่คอมไพล์เป็นภาษาเครื่องที่มีประสิทธิภาพได้ และกระบวนการแปลนี้ย่อมใช้เวลา โดยเฉพาะเมื่อมีการทำ optimization
อย่างไรก็ตาม เวลาในการคอมไพล์ของ Rust ไม่ได้แย่อย่างที่คิด และมีเหตุผลให้เชื่อว่าจะดีขึ้นได้อีกในอนาคต หากเทียบโปรเจ็กต์ขนาดใกล้เคียงกันด้วย C++ และ Rust โดยทั่วไปเวลาที่ใช้คอมไพล์ทั้งโปรเจ็กต์ถือว่าใกล้เคียงกัน สาเหตุหลักที่ทำให้รู้สึกว่า Rust คอมไพล์ช้าคือ C++ กับ Rust มีโมเดลการคอมไพล์ต่างกัน กล่าวคือ หน่วยการคอมไพล์ของ C++ คือไฟล์เดียว แต่ของ Rust คือ crate ที่ประกอบด้วยหลายไฟล์ ดังนั้นระหว่างพัฒนา หากแก้ไฟล์ C++ เพียงไฟล์เดียว เวลาคอมไพล์อาจลดลงมากเมื่อเทียบกับ Rust ขณะนี้มีงานขนาดใหญ่ที่กำลังรีแฟกเตอร์คอมไพเลอร์ Rust เพื่อให้รองรับ incremental compilation และเมื่อเสร็จแล้ว เวลาในการคอมไพล์ของ Rust ก็น่าจะดีขึ้นในลักษณะเดียวกับโมเดลของ C++
นอกเหนือจากโมเดลการคอมไพล์แล้ว การออกแบบภาษาของ Rust ยังมีหลายปัจจัยที่ส่งผลต่อเวลาในการคอมไพล์
อย่างแรก Rust มีระบบชนิดข้อมูลที่ค่อนข้างซับซ้อน และต้องใช้เวลาในการคอมไพล์ไม่น้อยเพื่อบังคับใช้ข้อจำกัดต่าง ๆ ที่ทำให้ Rust ปลอดภัยในขณะรันไทม์
อย่างที่สอง คอมไพเลอร์ Rust มีหนี้ทางเทคนิคเก่าอยู่ และโดยเฉพาะคุณภาพของ LLVM IR ที่สร้างออกมายังไม่ดีนัก ทำให้ LLVM ต้องใช้เวลาเพื่อ “แก้” มัน ในอนาคต ขั้นตอน optimization และการแปลที่อิงกับ MIR อาจช่วยลดภาระที่ Rust compiler โยนให้ LLVM ได้
อย่างที่สาม การที่ Rust ใช้ LLVM สำหรับการสร้างโค้ดนั้นเป็นดาบสองคม ด้วย LLVM ทำให้ Rust แสดงประสิทธิภาพรันไทม์ระดับโลกได้ แต่ LLVM เป็นเฟรมเวิร์กขนาดใหญ่ที่ไม่ได้โฟกัสเรื่องเวลาในการคอมไพล์ และเปราะบางเป็นพิเศษต่ออินพุตคุณภาพต่ำ
สุดท้าย กลยุทธ์ที่ Rust ใช้กับชนิดข้อมูล generic โดยทำ monomorphise คล้ายกับ C++ ช่วยให้ได้โค้ดที่เร็ว แต่ก็มีปัญหาว่าต้องสร้างโค้ดจำนวนมากกว่ากลยุทธ์การแปลแบบอื่นอยู่พอสมควร การพองตัวของโค้ดนี้สามารถแลกเปลี่ยนข้อดีข้อเสียกับ dynamic dispatch ได้โดยใช้ trait object.
ที่แน่ ๆ คือโปรเจ็กต์ Rust กินพื้นที่ดิสก์มากตอนบิลด์จริง ๆ ครับ ผมยังจำได้ว่าตกใจเลยตอนเห็นว่าโปรเจ็กต์ที่ดึงไลบรารีมาใช้เป็นร้อยตัว ใช้พื้นที่ไปประมาณ 2GB เข้าแล้ว...