ความเร็วในการคอมไพล์ Java เทียบกับความเร็วในการคอมไพล์ Scala


101

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

แต่ฉันมาจาก Java ซึ่งตามที่ฉันเข้าใจมันเร็วกว่าภาษาคอมไพล์อื่น ๆ และเร็วเพราะเหตุผลที่ฉันเปลี่ยนมาใช้ Scala (มันเป็นภาษาที่ง่ายมาก)

ฉันจึงอยากถามว่าฉันจะทำให้ Scala คอมไพล์เร็วขึ้นได้ไหมและ scalac จะเร็วเท่า javac


ดูเหมือนว่าผู้ใช้บางคนจะเห็นด้วยกับคุณ;) twitter.com/etorreborre/status/21286172202
VonC

ไปคอมไพล์เร็วกว่า Java เร็วขึ้นซึ่งกำลังพูดอะไรบางอย่าง
Daniel C. Sobral

Ahaha ในกรณีของฉันมันใช้เวลาหลายนาทีในการรวบรวม scalac โดยเฉลี่ยโดยมี LOC ไม่กี่ houndreds fsc จะเร็วกว่าเล็กน้อย
Jeriho

คำตอบ:


57

คอมไพลเลอร์ Scala มีความซับซ้อนกว่า Java โดยให้การอนุมานประเภทการแปลงโดยนัยและระบบประเภทที่มีประสิทธิภาพมากกว่า คุณสมบัติเหล่านี้ไม่ได้มาฟรีดังนั้นฉันไม่คาดหวังว่า scalac จะเร็วเท่า javac สิ่งนี้สะท้อนถึงการแลกเปลี่ยนระหว่างโปรแกรมเมอร์ที่ทำงานกับคอมไพเลอร์ที่ทำงาน

ที่กล่าวว่าเวลาคอมไพล์ดีขึ้นอย่างเห็นได้ชัดจาก Scala 2.7 เป็น Scala 2.8 และฉันคาดว่าการปรับปรุงจะดำเนินต่อไปในขณะนี้ฝุ่นได้ตกลงที่ 2.8 แล้ว หน้านี้จัดทำเอกสารเกี่ยวกับความพยายามและแนวคิดอย่างต่อเนื่องในการปรับปรุงประสิทธิภาพของคอมไพเลอร์ Scala

Martin Odersky ให้รายละเอียดเพิ่มเติมในคำตอบของเขา


1
หน้านี้ไม่มีอีกแล้ว ( lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded )?
VonC

ฉันเปลี่ยนจาก netbeans เป็น ant + jedit (ฉันรู้ว่าฉันรู้ว่ามดมีไว้สำหรับมนุษย์ถ้ำ แต่ฉันจะพัฒนาตามเวลาของฉันเอง) เพื่อที่ฉันจะได้ใช้ fsc แต่ฉันสงสัยว่าความเร็วในการรวบรวม Clojure เปรียบเทียบกับ Scala ได้อย่างไร? ดูเหมือนว่าจะมีคุณสมบัติมากมายใน Scala แต่ฉันคิดว่าไวยากรณ์นั้นง่ายกว่ามากในการแยกวิเคราะห์
user405163

1
เรากำลังออกหัวข้อที่นี่ แต่คอมไพเลอร์ของ Clojure นั้นเร็วมาก (เร็วกว่า javac ในแหล่งที่มาที่เท่ากันมาก) คุณพูดถูกว่ามันเป็นภาษาที่เรียบง่ายจริงๆและไม่มีระบบประเภทคงที่ซึ่งช่วยได้ไม่น้อย
Daniel Spiewak

458

มีสองด้านสำหรับความเร็ว (ขาด) สำหรับคอมไพเลอร์ Scala

  1. ค่าใช้จ่ายในการเริ่มต้นที่มากขึ้น

    • Scalac เองประกอบด้วยคลาสมากมายที่ต้องโหลดและคอมไพล์ jit

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

    โดยรวมแล้วคาดว่าค่าใช้จ่ายในการเริ่มต้นของ scalac จะอยู่ที่ 4-8 วินาทีนานขึ้นหากคุณเรียกใช้ในครั้งแรกเพื่อไม่ให้ดิสก์แคชเต็ม

    คำตอบของ Scala สำหรับค่าใช้จ่ายในการเริ่มต้นคือใช้ fsc หรือสร้างแบบต่อเนื่องกับ sbt จำเป็นต้องกำหนดค่า IntelliJ เพื่อใช้ตัวเลือกใดตัวเลือกหนึ่งมิฉะนั้นค่าใช้จ่ายแม้ในไฟล์ขนาดเล็กจะใหญ่เกินสมควร

  2. ความเร็วในการรวบรวมช้าลง Scalac จัดการได้ประมาณ 500 ถึง 1,000 เส้น / วินาที Javac จัดการได้ประมาณ 10 เท่า มีเหตุผลหลายประการนี้.

    • การอนุมานประเภทมีค่าใช้จ่ายสูงโดยเฉพาะอย่างยิ่งหากเกี่ยวข้องกับการค้นหาโดยนัย

    • Scalac ต้องทำการตรวจสอบประเภทสองครั้ง หนึ่งครั้งตามกฎของ Scala และครั้งที่สองหลังจากลบตามกฎของ Java

    • นอกจากการตรวจสอบประเภทแล้วยังมีขั้นตอนการแปลงอีกประมาณ 15 ขั้นตอนจาก Scala เป็น Java ซึ่งต้องใช้เวลาทั้งหมด

    • โดยทั่วไปแล้ว Scala จะสร้างคลาสเพิ่มขึ้นมากมายต่อขนาดไฟล์ที่กำหนดมากกว่า Java โดยเฉพาะอย่างยิ่งหากมีการใช้สำนวนการทำงานอย่างหนัก การสร้าง Bytecode และการเขียนคลาสต้องใช้เวลา

    ในทางกลับกันโปรแกรม Scala 1,000 บรรทัดอาจสอดคล้องกับโปรแกรม Java 2-3K บรรทัดดังนั้นความเร็วที่ช้าลงบางส่วนเมื่อนับเป็นบรรทัดต่อวินาทีจะต้องสมดุลกับฟังก์ชันการทำงานที่มากขึ้นต่อบรรทัด

    เรากำลังดำเนินการปรับปรุงความเร็ว (เช่นการสร้างไฟล์คลาสแบบขนาน) แต่ไม่มีใครคาดคิดว่าจะมีปาฏิหาริย์ที่ด้านหน้านี้ Scalac จะไม่เร็วเท่า javac ฉันเชื่อว่าโซลูชันจะอยู่ในเซิร์ฟเวอร์คอมไพล์เช่น fsc ร่วมกับการวิเคราะห์การพึ่งพาที่ดีเพื่อให้มีการคอมไพล์ไฟล์เพียงชุดเล็ก ๆ เท่านั้น เรากำลังดำเนินการอยู่เช่นกัน


1
เกี่ยวกับค่าใช้จ่ายในการเริ่มต้นเนื่องจากการโหลดคลาส: การคอมไพล์โค้ดเนทีฟล่วงหน้าโดยใช้ GCJ หรือ Mono ช่วยหรือไม่
หอยทาก

15
จะเกิดอะไรขึ้นถ้า Scala ถูกเขียนใหม่ใน C ++? : o)
marcus

การใช้คำสั่ง invokedynamic bytecode จะมีประโยชน์หรือไม่?
Rob Grant

40

คุณควรทราบว่าการคอมไพล์ Scala ใช้เวลาอย่างน้อยตามลำดับขนาดที่ยาวกว่า Java ในการคอมไพล์ เหตุผลดังต่อไปนี้:

  1. หลักการตั้งชื่อ (ไฟล์XY.scalaไฟล์ไม่จำเป็นต้องมีคลาสที่เรียกXYและอาจมีคลาสระดับบนสุดหลายคลาส) คอมไพลเลอร์อาจต้องค้นหาไฟล์ต้นฉบับเพิ่มเติมเพื่อค้นหาตัวระบุคลาส / ลักษณะ / อ็อบเจ็กต์ที่กำหนด
  2. นัย - การใช้นัยอย่างหนักหมายความว่าคอมไพเลอร์จำเป็นต้องค้นหาการแปลงโดยนัยใด ๆ ในขอบเขตสำหรับวิธีการที่กำหนดและจัดอันดับให้พบว่า "ถูกต้อง" ( กล่าวคือคอมไพเลอร์มีโดเมนการค้นหาที่เพิ่มขึ้นอย่างมากเมื่อค้นหาวิธีการ )
  3. ระบบประเภท - ระบบประเภทสกาลามีความซับซ้อนกว่าของ Java และด้วยเหตุนี้จึงใช้เวลา CPU มากกว่า
  4. การอนุมานประเภท - การอนุมานประเภทมีราคาแพงในการคำนวณและเป็นงานที่javacไม่จำเป็นต้องทำเลย
  5. scalacรวมถึงเครื่องจำลอง 8 บิตของสถานีรบที่มีอาวุธครบมือและปฏิบัติการซึ่งสามารถดูได้โดยใช้คีย์ผสม CTRL-ALT-F12 ในช่วงการรวบรวมGenICode

3
@obox_lakes, เกลียดการ nitpick แต่ Java ไม่จำเป็นที่จะต้องทำอนุมานชนิดสำหรับวิธีการแปรแล้วint a<T>(T a) {} james-iry.blogspot.com/2009/04/…a(pls_infer_my_type)
Elazar Leibovich

13
@ เอลาซาร์ - ใช่ฉันรู้ แต่เป็นเรื่องที่น่าหัวเราะอย่างตรงไปตรงมาถัดจากสกาล่าเรียกสิ่งนี้ว่า "การอนุมานประเภท"!
oxbow_lakes


19

วิธีที่ดีที่สุดในการทำ Scala คือ IDEA และ SBT ตั้งค่าโปรเจ็กต์ SBT พื้นฐาน (ซึ่งจะทำเพื่อคุณถ้าคุณต้องการ) และเรียกใช้ในโหมดคอมไพล์อัตโนมัติ (คำสั่ง~compile) และเมื่อคุณบันทึกโปรเจ็กต์ SBT จะคอมไพล์ใหม่

คุณยังสามารถใช้ปลั๊กอิน SBT สำหรับ IDEA และแนบการดำเนินการ SBT กับการกำหนดค่าการเรียกใช้แต่ละรายการของคุณ ปลั๊กอิน SBT ยังมีคอนโซล SBT แบบโต้ตอบภายใน IDEA

ไม่ว่าจะด้วยวิธีใดก็ตาม (SBT ที่ทำงานจากภายนอกหรือปลั๊กอิน SBT) SBT จะยังคงทำงานอยู่ดังนั้นคลาสทั้งหมดที่ใช้ในการสร้างโปรเจ็กต์ของคุณจะได้รับ "การอุ่นเครื่อง" และ JIT-ed และค่าโสหุ้ยในการเริ่มต้นระบบจะถูกตัดออก นอกจากนี้ SBT ยังรวบรวมเฉพาะไฟล์ต้นฉบับที่จำเป็นเท่านั้น เป็นวิธีที่มีประสิทธิภาพมากที่สุดในการสร้างโปรแกรม Scala


9

การแก้ไขล่าสุดของScala-IDE (Eclipse) นั้นดีกว่ามากในการจัดการการคอมไพล์แบบเพิ่มหน่วย

ดู " ระบบสร้าง Scala ที่ดีที่สุดคืออะไร " สำหรับข้อมูลเพิ่มเติม


วิธีแก้ปัญหาอื่นคือการรวมfsc - คอมไพเลอร์ออฟไลน์ที่รวดเร็วสำหรับภาษา Scala 2 - (ตามภาพประกอบในบล็อกโพสต์นี้) เป็นตัวสร้างใน IDE ของคุณ

ข้อความแสดงแทน

แต่ไม่ใช่ในEclipse โดยตรงอย่างที่Daniel Spiewakกล่าวไว้ในความคิดเห็น:

คุณไม่ควรใช้ FSC ภายใน Eclipse โดยตรงหากเป็นเพียงเพราะ Eclipse ใช้ FSC ใต้พื้นผิวอยู่แล้ว
FSC นั้นเป็นชั้นบาง ๆ ที่อยู่ด้านบนของคอมไพเลอร์ที่อยู่อาศัยซึ่งเป็นกลไกที่ Eclipse ใช้ในการรวบรวมโครงการ Scala อย่างแม่นยำ


ในที่สุดJackson Davisเตือนฉันในความคิดเห็น:

sbt (Simple build Tool)ยังรวมการคอมไพล์แบบ "ส่วนเพิ่ม" บางประเภทด้วย (ผ่านการเรียกใช้งาน ) แม้ว่าจะไม่สมบูรณ์แบบก็ตาม


2
sbt สามารถทำการคอมไพล์แบบเพิ่มหน่วยได้เช่นกัน
Jackson Davis

@ แจ็คสัน: เรียกการดำเนินการใช่ไหม! ฉันได้รวมไว้ในคำตอบของฉัน
VonC

2
คุณไม่ควรจะใช้ FSC ภายในคราสโดยตรงถ้าเพียงเพราะคราสแล้วใช้ FSC ภายใต้พื้นผิว FSC นั้นเป็นชั้นบาง ๆ ที่อยู่ด้านบนของคอมไพเลอร์ที่อยู่อาศัยซึ่งเป็นกลไกที่ Eclipse ใช้ในการรวบรวมโครงการ Scala อย่างแม่นยำ
Daniel Spiewak

1
FSC ย่อมาจาก Fast Scala Compiler ไม่ใช่ Fast Java Compiler
Ben McCann

@BenMcCann: อ๊ะ. ขวา. ฉันได้แก้ไขคำตอบแล้ว
VonC

6

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

ฉันไม่แน่ใจว่าปลั๊กอิน Netbeans scala รองรับ fsc หรือไม่ (เอกสารบอกอย่างนั้น) แต่ฉันไม่สามารถใช้งานได้ ลองสร้างปลั๊กอินทุกคืน


1
ปลั๊กอิน IntelliJ IDEA Scala ยังมีตัวเลือกในการใช้ fsc
Aaron Novstrup

1
@anovstrup: ใช่ แต่บางครั้งก็ขัดข้อง
Denis Tulskiy

4

คุณสามารถใช้ปลั๊กอิน JRebel ซึ่งฟรีสำหรับ Scala ดังนั้นคุณสามารถ "พัฒนาในดีบักเกอร์" และ JRebel จะโหลดคลาสที่เปลี่ยนแปลงใหม่ทันที

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

ถ้าไม่จำเป็นต้องเป็น Scala 100% แต่ก็คล้าย ๆ กันด้วยคุณอาจให้Kotlinลอง

- โอลิเวอร์


2

ฉันแน่ใจว่าสิ่งนี้จะได้รับการโหวตลดลง แต่การหมุนเวียนอย่างรวดเร็วไม่ได้เอื้อต่อคุณภาพหรือผลผลิตเสมอไป

ใช้เวลาในการคิดอย่างรอบคอบมากขึ้นและดำเนินการตามวงจรย่อยของการพัฒนาน้อยลง รหัส Scala ที่ดีมีความหนาแน่นและจำเป็นมากกว่า (กล่าวคือปราศจากรายละเอียดและความซับซ้อนโดยบังเอิญ) ต้องใช้ความคิดมากกว่านี้และต้องใช้เวลา (อย่างน้อยก็ในตอนแรก) คุณสามารถดำเนินการได้ดีโดยใช้รอบการทดสอบโค้ด / การทดสอบ / การดีบักที่น้อยลงซึ่งจะนานขึ้นเล็กน้อยและยังคงปรับปรุงประสิทธิภาพการทำงานและคุณภาพของงานของคุณ

กล่าวโดยย่อ: ค้นหารูปแบบการทำงานที่ดีที่สุดที่เหมาะกับ Scala


3
ฉันยอมรับว่ามันไม่จำเป็นที่จะต้องหมุนรอบตัวเองอย่างรวดเร็ว แต่มันไม่เจ็บใช่มั้ย?
Elazar Leibovich

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

9
ฉันคิดว่าประสิทธิภาพส่วนใหญ่ของฉันสูญเสียไปกับการคิดมากก่อนที่จะวิ่ง ฉันมักจะพบว่าตัวเองกำลังมองหาสมการบางอย่างเป็นระยะเวลานานโดยพยายามมองหาว่าหลุมพรางที่อาจเกิดขึ้นกำลังรอฉันอยู่ในขณะที่ฉันคิดว่า "แค่เรียกใช้!" ที่ด้านหลังศีรษะของฉัน และแน่นอนว่าเมื่อฉันเรียกใช้โปรแกรมฉันได้เรียนรู้มากกว่าที่ฉันจะได้ทำสมาธิอีกชั่วโมงหรือสองชั่วโมง การทำสมาธิเป็นสิ่งที่ดี แต่ฉันรู้สึกว่าฉันใช้การรวบรวม / การทำสมาธิแบบเพิ่มหน่วยด้วย java ได้อย่างเหมาะสมที่สุด
user405163

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