Przede wszystkim chciałbym wyjaśnić, że nie jest to pytanie język-X-język-Y, aby ustalić, który jest lepszy.
Używam Javy od dłuższego czasu i zamierzam nadal z niej korzystać. Równolegle uczę się Scali z wielkim zainteresowaniem: poza drobnymi rzeczami, które przyzwyczajają się do mojego wrażenia, to, że naprawdę mogę bardzo dobrze pracować w tym języku.
Moje pytanie brzmi: w jaki sposób oprogramowanie napisane w Scali różni się od oprogramowania napisanego w Javie pod względem szybkości wykonywania i zużycia pamięci? Oczywiście trudno jest odpowiedzieć na to pytanie, ale spodziewałbym się, że konstrukcje wyższego poziomu, takie jak dopasowanie wzorca, funkcje wyższego rzędu itp., Wprowadzą pewne narzuty.
Jednak moje obecne doświadczenie w Scali jest ograniczone do małych przykładów poniżej 50 linii kodu i do tej pory nie przeprowadziłem żadnych testów porównawczych. Więc nie mam prawdziwych danych.
Jeśli okazało się, że Scala ma trochę narzutów w Javie, czy ma sens mieszane projekty Scala / Java, w których koduje się bardziej złożone części w Scali i części krytyczne pod względem wydajności w Javie? Czy to powszechna praktyka?
EDYCJA 1
Przeprowadziłem mały test porównawczy: zbuduj listę liczb całkowitych, pomnóż każdą liczbę całkowitą przez dwa i umieść ją na nowej liście, wydrukuj wynikową listę. Napisałem implementację Java (Java 6) i implementację Scala (Scala 2.9). Uruchomiłem oba na Eclipse Indigo pod Ubuntu 10.04.
Wyniki są porównywalne: 480 ms dla Javy i 493 ms dla Scali (średnio ponad 100 iteracji). Oto fragmenty, których użyłem.
// Java
public static void main(String[] args)
{
long total = 0;
final int maxCount = 100;
for (int count = 0; count < maxCount; count++)
{
final long t1 = System.currentTimeMillis();
final int max = 20000;
final List<Integer> list = new ArrayList<Integer>();
for (int index = 1; index <= max; index++)
{
list.add(index);
}
final List<Integer> doub = new ArrayList<Integer>();
for (Integer value : list)
{
doub.add(value * 2);
}
for (Integer value : doub)
{
System.out.println(value);
}
final long t2 = System.currentTimeMillis();
System.out.println("Elapsed milliseconds: " + (t2 - t1));
total += t2 - t1;
}
System.out.println("Average milliseconds: " + (total / maxCount));
}
// Scala
def main(args: Array[String])
{
var total: Long = 0
val maxCount = 100
for (i <- 1 to maxCount)
{
val t1 = System.currentTimeMillis()
val list = (1 to 20000) toList
val doub = list map { n: Int => 2 * n }
doub foreach ( println )
val t2 = System.currentTimeMillis()
println("Elapsed milliseconds: " + (t2 - t1))
total = total + (t2 - t1)
}
println("Average milliseconds: " + (total / maxCount))
}
Tak więc w tym przypadku wydaje się, że narzut Scala (użycie zasięgu, mapy, lambda) jest naprawdę minimalny, co nie jest dalekie od informacji dostarczonych przez Inżyniera Świata.
Może istnieją inne konstrukcje Scali, które należy stosować ostrożnie, ponieważ są szczególnie ciężkie do wykonania?
EDYCJA 2
Niektórzy z was zwrócili uwagę, że println w wewnętrznych pętlach zajmuje większość czasu wykonania. Usunąłem je i ustawiłem rozmiar list na 100000 zamiast 20000. Uzyskana średnia wyniosła 88 ms dla Javy i 49 ms dla Scali.