Im folgenden das Ergebnis eines Tests, mit dem ich die Geschwindigkeit der Laufzeitumgebungen von Java (Versionen 1.02 und 1.2), PHP (Versionen 3.0 und 4.0) und Perl (Version 5) verglichen habe. Diese Sprachen haben ich ausgewählt, weil sie zu den verbreitetsten im Bereich serverseitige Web-Programmierung gehören. ASP wurde nicht einbezogen, da ich selbst es nicht benutze und deswegen weder die Sprache kenne noch eine Laufzeitumgebung dafür zur Verfügung habe. Beim Testen wurden verschiedene simple Vorgänge sehr häufig wiederholt. Die Zeiten für den Compilier-Vorgang wie er in PHP und Perl erst zur Laufzeit stattfindet, sind nicht in das Ergebnis eingegangen. Da es um einen Vergleich der Laufzeitumgebungen und nicht von bestehenden Funktionen der APIs ging, wurde, soweit möglich, auf den Einsatz von bestehenden Funktionen verzichtet und stattdessen Befehle verwendet, die direkt zur Syntax der jeweiligen Sprache gehören. Auf die Verwendung identischer Werte wurde beachtet (z.B. beim Sortieren oder dem Vergleich von Zeichenketten). Alle Compiler bzw. Interpreter wurden mit ihren Standardeinstellungen aufgerufen. Die Zeitangaben beziehen sich auf einen Rechner mit 750Mhz und wurden unter Win98 durchgeführt. Da es jedoch nicht um die absoluten Werte, sondern um den Vergleich unter identischen Bedingungen geht, dürfte das keine Rolle spielen. Alle Zeitangaben sind in Sekunden.
Die Quellcodes für den Test können hier runtergeladen werden.
Aufgabe: | JDK 1.02 | JDK 1.22 | PHP 3 | PHP 4 | Perl 5 |
---|
Arithmetische Operationen: Zählen von 1 bis 40 Mio. | 8 | 0 | 273 | 43 | 23 | Arithmetische Operationen: Sortieren eines Arrays mit 3.000 Zahlen. | 5 | 1 | 197 | 39 | 15 | Arithmetische Operationen: 10 Mio. Additionen mit Kleinen-, Mittleren-, Großen- sowie Fließkommazahlen (in Java: byte, int, long, float). | 3/3/5/4 | 0/0/0/0 | 161/160/161/160 | 28/27/28/28 | 9/10/9/9 | Arithmetische Operationen: 10 Mio. Multiplikationen mit Kleinen-, Mittleren-, Großen- sowie Fließkommazahlen (in Java: byte, int, long, float). | 4/3/4/5 | 0/0/0/0 | 160/160/160/160 | 28/27/28/28 | 10/10/9/10 | Funktionsaufrufe: 4 Mio. Aufrufe einer eigenen Funktion mit einer Zahl als Parameter, einer Zeichenkette als Parameter, einer Zahl plus Rückgabe derselben und einer Zeichenkette plus Rückgabe derselben. | 1/2/2/3 | 0/0/0/0 | 91/92/112/114 | 26/26/26/25 | 8/8/15/17 | Zeichenkettenoperationen: Vergleich auf Gleichheit von je 52 Zeichenketten zu je 200000 Zeichen mit einander (jede mit jeder). Um den Vergleich möglichst aufwendig zu gestalten, waren die ersten 199999 Zeichen aller Zeichenketten identisch. | 278 | 10 | 17 | 6 | 2 | Zeichenkettenoperationen: Zusammensetzen einer Zeichenkette indem eine anfänglich 52 Zeichen lange Zeichenkette 15 mal an sich selbst angehängt wird (also auf 1703936 Zeichen anwächst). Der Vorgang wird 800 mal wiederholt. | 91 | 130 | 51 | 25 | 9 | Zeichenkettenoperationen: Aus einer 1703936 langen Zeichenkette wird 17 Mio. mal an verschiedenen Stellen ein Zeichenkette der Länge 5 übernommen (substring). | 61 | 11 | Abbruch | 137 | 25 | Zeichenkettenoperationen: Umwandlung von 3 Mio als Zeichenkette vorliegende Ganzzahlen in eine numerische Ganzzahl (int). Selbiges mit Fließkomma. Vorgänge je 100 mal wiederholt. | 56/55 | 4/28 | 59/71 | 14/24 | 4/5 |
Bemerkungen:
- Die Überlegenheit von Java bei arithmetischen Operationen führen ich auf die Verwendung von Datentypen zurück. Zwar notiert auch PHP intern numerische Werte als Zahlen, jedoch kann hier der Datentyp einer Variablen dynamisch wechseln, was zu einem vermehrten Verwaltungsaufwand fuehrt. Möglicherweise liegt der Grund für die Betulichkeit von PHP auch in der interen Verwaltung der Variablen, die generell den Zugriff darauf langsamer macht. Zumindest ist eine Rechenoperation mit Literalen (
$x = 2 * 3 ) etwas schneller als mit Variablen ($x= $a * $b ). - Das schlechte Abschneiden von Java bei Zeichenketten-Operationen liegt teilweise wohl daran, daß Java Zeichenketten als Unicode speichert, deswegen 16 Bits pro Zeichen (statt 8) verwendet und entsprechend mehr Aufwand betreiben muß. Der Hauptgrund ist aber vermutlich, daß in Java jede Zeichenkette ein Objekt ist und der beim Erzeugen von Objekten zu betreibende Aufwand recht groß ist.
Daß Java1.2 beim Verknüpfen von Zeichenketten dann aber sogar langsamer ist, als Java1.02, wundert mich doch sehr. Für eine schnellere Verknüpfung von Zeichenketten bietet Java übrigens die StringBuffer-Klasse, die jedoch hier der wegen der Vergleichbarkeit der Testbedingungen nicht benutzt wird. - Die deutliche Performance-Steigerung von Java1.2 gegenüber 1.02 ist maßgeblich auf den ab der Version 1.1 integrierten Just-In-Time-Compiler (JIT) zurückzuführen. Dieser wandelt den vom Compiler erzeugten Byte-Code zur Laufzeit in echte Maschinensprache-Befehle um, wodurch Java fast die Geschwindigkeit von nativen Programmen (z.B. in C++ geschriebenen) erreicht.
- Ebenfalls beachtlich ist die Steigerung von PHP 4 gegenüber PHP 3. Worauf diese zurückzuführen ist, weiß ich allerdings nicht. Vermutlich handelt es sich dabei um im Verlauf der Weiterentwicklung (im Vergleich zu Perl ist PHP eine recht junge Sprache) erworbene Optimierungen.
|