Szybkość kompilacji Java a szybkość kompilacji Scala

101

Od jakiegoś czasu programuję w Scali i podoba mi się to, ale denerwuje mnie tylko czas kompilacji programów. Wydaje się, że to drobiazg, ale w Javie mogłem wprowadzić drobne zmiany w moim programie, kliknąć przycisk uruchamiania w netbeanach i BOOM, działa, a kompilacja w scali z czasem wydaje się pochłaniać dużo czasu. Słyszałem, że przy wielu dużych projektach język skryptowy staje się bardzo ważny ze względu na czas potrzebny na kompilację, potrzebę, której nie widziałem, gdy używałem Javy.

Ale pochodzę z Javy, która, jak rozumiem, jest szybsza niż jakikolwiek inny język kompilowany i jest szybka z powodów, dla których przesiadłem się na Scala (jest to bardzo prosty język).

Chciałem więc zapytać, czy mogę sprawić, by Scala kompilowała się szybciej i czy scalac będzie kiedykolwiek tak szybki jak javac.

user405163
źródło
Wygląda na to, że niektórzy użytkownicy się z tobą zgadzają;) twitter.com/etorreborre/status/21286172202
VonC
Go kompiluje się szybciej niż Java. O wiele szybciej, czyli coś mówi.
Daniel C. Sobral
Ahaha, w moim przypadku przeciętna kompilacja scalaca z kilkoma setkami LOC zajmuje kilka minut, fsc jest nieco szybsza.
Jeriho

Odpowiedzi:

57

Kompilator Scala jest bardziej wyrafinowany niż Java, zapewniając wnioskowanie o typach, niejawną konwersję i znacznie potężniejszy system typów. Te funkcje nie są dostępne za darmo, więc nie spodziewałbym się, że scalac kiedykolwiek będzie tak szybki jak javac. Odzwierciedla to kompromis między programistą wykonującym pracę a kompilatorem wykonującym pracę.

To powiedziawszy, czasy kompilacji już wyraźnie się poprawiły, przechodząc ze Scali 2.7 do Scala 2.8 i spodziewam się, że ulepszenia będą kontynuowane teraz, gdy pył opadł na 2.8. Ta strona dokumentuje niektóre z bieżących wysiłków i pomysłów mających na celu poprawę wydajności kompilatora Scala.

Martin Odersky podaje znacznie więcej szczegółów w swojej odpowiedzi.

Aaron Novstrup
źródło
1
Czy nie jest to więcej na tej stronie ( lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded )?
VonC
Przerzuciłem się z netbeans na ant + jedit (wiem, wiem, ant jest dla jaskiniowców, ale będę ewoluował w swoim własnym czasie), aby móc używać fsc. Ale zastanawiałem się, jak szybkość kompilacji Clojure wypada w porównaniu do Scali? Wydaje się, że ma wiele funkcji w Scali, ale wyobrażam sobie, że składnia jest znacznie łatwiejsza do przeanalizowania.
user405163
1
Jesteśmy tutaj trochę poza tematem, ale kompilator Clojure jest niesamowicie szybki (znacznie szybszy niż javac w równoważnych źródłach). Masz rację, że jest to naprawdę prosty język i nie ma żadnego statycznego systemu typów, co bardzo pomaga.
Daniel Spiewak
458

Istnieją dwa aspekty (braku) szybkości kompilatora Scala.

  1. Większe koszty początkowe

    • Sam Scalac składa się z WIELU klas, które muszą zostać załadowane i skompilowane w jit

    • Scalac musi przeszukać ścieżkę klas dla wszystkich pakietów i plików głównych. W zależności od rozmiaru ścieżki klas może to zająć od jednej do trzech dodatkowych sekund.

    Ogólnie rzecz biorąc, spodziewaj się obciążenia startowego skalac 4-8 sekund, dłuższego, jeśli uruchomisz go po raz pierwszy, aby pamięci podręczne dysku nie zostały zapełnione.

    Odpowiedzią Scali na obciążenie początkowe jest użycie fsc lub ciągłe budowanie z sbt. IntelliJ musi być skonfigurowany do używania którejkolwiek z opcji, w przeciwnym razie jego narzut, nawet w przypadku małych plików, jest nieracjonalnie duży.

  2. Wolniejsza prędkość kompilacji. Scalac zarządza około 500 do 1000 linii / sek. Javac radzi sobie około 10 razy tyle. Dzieje się tak z kilku powodów.

    • Wnioskowanie o typie jest kosztowne, zwłaszcza jeśli obejmuje wyszukiwanie niejawne.

    • Scalac musi dwukrotnie sprawdzać typ; raz według reguł Scali i drugi raz po skasowaniu według reguł Javy.

    • Oprócz sprawdzania typów istnieje około 15 kroków transformacji, aby przejść ze Scali do Javy, które wymagają czasu.

    • Scala zazwyczaj generuje o wiele więcej klas na dany rozmiar pliku niż Java, w szczególności jeśli często używane są idiomy funkcjonalne. Generowanie kodu bajtowego i pisanie klas wymaga czasu.

    Z drugiej strony, 1000-wierszowy program Scala może odpowiadać 2-3-kilometrowemu programowi w języku Java, więc część wolniejszej szybkości liczonej w wierszach na sekundę musi być równoważona większą funkcjonalnością na wiersz.

    Pracujemy nad poprawą szybkości (np. Poprzez równoległe generowanie plików klas), ale nie można oczekiwać cudów na tym froncie. Scalac nigdy nie będzie tak szybki jak javac. Uważam, że rozwiązaniem będzie kompilacja serwerów, takich jak fsc, w połączeniu z dobrą analizą zależności, tak aby tylko minimalny zestaw plików musiał zostać ponownie skompilowany. Nad tym też pracujemy.

Martin Odersky
źródło
1
O narzutu uruchamiania spowodowanym ładowaniem klas: czy kompilacja z wyprzedzeniem do kodu natywnego przy użyciu pomocy GCJ lub Mono?
Ślimak mechaniczny
15
A co by było, gdyby Scala została przepisana w C ++? : o)
marcus
Czy skorzystanie z wywołania dynamicznej instrukcji kodu bajtowego przyniesie korzyści?
Rob Grant
40

Należy pamiętać, że kompilacja Scala trwa co najmniej o rząd wielkości dłużej niż kompilacja Java. Przyczyny tego są następujące:

  1. Konwencje nazewnictwa (plik XY.scalanie musi zawierać klasy o nazwie XYi może zawierać wiele klas najwyższego poziomu). Dlatego kompilator może być zmuszony do przeszukania większej liczby plików źródłowych, aby znaleźć dany identyfikator klasy / cechy / obiektu.
  2. Implicits - intensywne użycie implicits oznacza, że ​​kompilator musi przeszukać każdą niejawną konwersję w zakresie dla danej metody i uszeregować je, aby znaleźć „właściwą”. ( tj. kompilator ma znacznie zwiększoną domenę wyszukiwania podczas lokalizowania metody ).
  3. System typów - system typów Scala jest znacznie bardziej skomplikowany niż system Java i dlatego zajmuje więcej czasu procesora.
  4. Wnioskowanie o typie - wnioskowanie o typie jest kosztowne obliczeniowo i jest zadaniem, które w javacogóle nie musi być wykonywane
  5. scalaczawiera 8-bitowy symulator w pełni uzbrojonej i operacyjnej stacji bojowej, który można przeglądać za pomocą kombinacji klawiszy magicznych CTRL-ALT-F12 podczas fazy kompilacji GenICode .
oxbow_lakes
źródło
3
@obox_lakes, nienawidzę przyczepić, ale Java ma potrzebę zrobienia typu wnioskowanie o parametrycznych metod int a<T>(T a) {}i potem a(pls_infer_my_type). james-iry.blogspot.com/2009/04/…
Elazar Leibovich
13
@Elazar - tak, wiem. Ale szczerze mówiąc śmiesznym jest nazywanie tego „wnioskowania o typie” obok scali!
oxbow_lakes
19

Najlepszym sposobem na zrobienie Scali jest IDEA i SBT. Skonfiguruj elementarny projekt SBT (który zrobi za Ciebie, jeśli chcesz) i uruchom go w trybie automatycznej kompilacji (polecenie ~compile), a kiedy zapiszesz projekt, SBT dokona ponownej kompilacji.

Możesz również użyć wtyczki SBT dla IDEA i dołączyć akcję SBT do każdej z Konfiguracji Run. Wtyczka SBT zapewnia również interaktywną konsolę SBT w ramach IDEA.

Tak czy inaczej (SBT działające zewnętrznie lub wtyczka SBT), SBT pozostaje uruchomione, a zatem wszystkie klasy używane do budowania projektu są „rozgrzewane” i poddawane JIT, a narzut związany z uruchomieniem zostaje wyeliminowany. Ponadto SBT kompiluje tylko pliki źródłowe, które tego potrzebują. Jest to zdecydowanie najbardziej efektywny sposób tworzenia programów Scala.

Randall Schulz
źródło
9

Najnowsze wersje Scala-IDE (Eclipse) znacznie lepiej radzą sobie z zarządzaniem kompilacją przyrostową.

Zobacz „ Jaki jest najlepszy system kompilacji Scala? ”, Aby uzyskać więcej informacji.


Innym rozwiązaniem jest integracja fsc - szybkiego kompilatora offline dla języka Scala 2 - (jak pokazano w tym wpisie na blogu ) jako kreatora w swoim IDE.

tekst alternatywny

Ale nie bezpośrednio w Eclipse, o czym Daniel Spiewak wspomina w komentarzach:

Nie powinieneś używać FSC bezpośrednio w Eclipse, choćby dlatego, że Eclipse już używa FSC pod powierzchnią.
FSC to w zasadzie cienka warstwa na wierzchu kompilatora rezydentnego, który jest dokładnie mechanizmem używanym przez Eclipse do kompilowania projektów Scala.


Wreszcie, jak przypomina mi Jackson Davis w komentarzach:

sbt (narzędzie do prostego budowania) zawiera również pewnego rodzaju kompilację „przyrostową” (poprzez wykonanie wyzwalane ), mimo że nie jest doskonała , a ulepszona kompilacja przyrostowa jest w przygotowaniu do nadchodzącej wersji 0.9 sbt.

VonC
źródło
2
sbt może również kompilować przyrostowe
Jackson Davis,
@Jackson: wyzwolone wykonanie, prawda! Zawarłem to w mojej odpowiedzi.
VonC,
2
Nie powinieneś używać FSC bezpośrednio w Eclipse, choćby dlatego, że Eclipse już używa FSC pod powierzchnią. FSC to w zasadzie cienka warstwa na kompilatorze rezydentnym, który jest dokładnie mechanizmem używanym przez Eclipse do kompilowania projektów Scala.
Daniel Śpiewak
1
FSC oznacza Fast Scala Compiler - a nie Fast Java Compiler
Ben McCann
@BenMcCann: ups. Dobrze. Naprawiłem odpowiedź.
VonC
6

Użyj fsc - jest to szybki kompilator scala, który działa w tle i nie wymaga ciągłego ładowania. Może ponownie wykorzystać poprzednią instancję kompilatora.

Nie jestem pewien, czy wtyczka Netbeans scala obsługuje fsc (tak mówi dokumentacja), ale nie mogłem go uruchomić. Wypróbuj nocne kompilacje wtyczki.

Denis Tulskiy
źródło
1
Wtyczka IntelliJ IDEA Scala ma również opcję użycia fsc
Aaron Novstrup
1
@anovstrup: tak, ale czasami się zawiesza.
Denis Tulskiy
4

Możesz użyć wtyczki JRebel, która jest bezpłatna dla Scala. Możesz więc w pewnym sensie „programować w debugerze”, a JRebel zawsze przeładuje zmienioną klasę na miejscu.

Przeczytałem gdzieś oświadczenie samego Martina Odersky'ego, w którym mówi on, że wyszukiwanie implicitów (kompilator musi upewnić się, że nie ma więcej niż jednej niejawnej dla tej samej konwersji, aby wykluczyć niejednoznaczności) może zająć kompilator. Dlatego dobrym pomysłem może być ostrożne obchodzenie się z implikacjami.

Jeśli nie musi to być w 100% Scala, ale coś podobnego, możesz spróbować Kotlin .

- Oliver

OlliP
źródło
2

Jestem pewien, że zostanie to przegłosowane, ale niezwykle szybki zwrot nie zawsze sprzyja jakości lub produktywności.

Poświęć czas na dokładniejsze przemyślenie i wykonaj mniej mikro-cykli programistycznych. Dobry kod Scala jest gęstszy i bardziej istotny (tj. Wolny od przypadkowych szczegółów i złożoności). Wymaga więcej przemyśleń, a to wymaga czasu (przynajmniej na początku). Możesz osiągnąć dobre postępy dzięki mniejszej liczbie cykli kodowania / testowania / debugowania, które są indywidualnie nieco dłuższe i nadal poprawiają produktywność i jakość pracy.

Krótko mówiąc: szukaj optymalnego wzoru roboczego, lepiej pasującego do Scala.

Randall Schulz
źródło
3
Zgadzam się, że nie jest konieczny szybki cykl zwrotów. Ale to nie boli, prawda?
Elazar Leibovich
27
Nie zamierzam głosować negatywnie, ale stwierdzenie, że powinieneś dostosować swój wzorzec pracy do ograniczeń swojego narzędzia (wolną prędkość kompilatora), zamiast próbować ulepszyć narzędzie, nie jest dobrym argumentem. Szczególnie umiejętność wykonywania szybkich cykli testowych jest bardzo cenna (chociaż nie zastępuje potrzeby głębokiego przemyślenia, tego rodzaju, które prawdopodobnie najlepiej robić z dala od klawiatury, to ładnie ją uzupełnia).
Thilo
9
Myślę, że większość mojej produktywności jest tracona na przemyślenie przed bieganiem. Często spoglądam na jakieś równanie przez długie okresy, próbując dostrzec potencjalną pułapkę, która na mnie czeka, a jednocześnie myślę: „Po prostu uruchom to!”. z tyłu mojej głowy. I rzeczywiście, kiedy uruchamiam program, uczę się o wiele więcej, niż prawdopodobnie miałbym przez kolejną godzinę lub dwie medytacji. Medytacja jest dobra, ale wydaje mi się, że mam bardzo optymalne wykorzystanie kompilacji przyrostowej / medytacji w Javie.
user405163
2
Jest to również podobne do sugerowania, że ​​Szekspir nie powinien używać modułu sprawdzania pisowni, a zamiast tego zastanowić się intensywniej nad tym, co chce powiedzieć. Automatyczny moduł sprawdzania pisowni pomaga w zupełnie innym zestawie problemów.
Thilo,