JRuby vs. Python vs. PHP vs. Ruby

Wysłane przez Marek Tenus (~marcus) dnia 13.01.2008

Pojawiła się wersja 1.1 RC jruby jest zatem powód do tego, aby sprawdzić, czy zapowiedzi co do szybkości i wydajności interpretera są prawdziwe. By jednak artykuł nie był zbyt subiektywny i lakoniczny, pozwoliłem sobie porównać kilka interpreterów Ruby z Pythonem i PHP w odniesieniu do szybkości ich działania. Artykuł ten jest kontynuacją benchmarków przeprowadzonych przez Jarosława Zabiełło (hipertracker ) „Python vs. Ruby 1.9 YARV. Cz. II" (polecam przed przeczytaniem tego artykułu zapoznać się z tym wątkiem).

Pojawiła się wersja 1.1 RC jruby jest zatem powód do tego, aby sprawdzić, czy zapowiedzi co do szybkości i wydajności interpretera są prawdziwe. By jednak artykuł nie był zbyt subiektywny i lakoniczny, pozwoliłem sobie porównać kilka interpreterów Ruby z Pythonem i PHP w odniesieniu do szybkości ich działania. Artykuł ten jest kontynuacją benchmarków przeprowadzonych przez Jarosława Zabiełło (hipertracker ) „Python vs. Ruby 1.9 YARV. Cz. II" (polecam przed przeczytaniem tego artykułu zapoznać się z tym wątkiem). Do testów wykorzystałem ten sam algorytm (patrz blog Zabiełły). Różnica moich benchmarków jest taka, że dodatkowo przetestowałem PHP (4i5) i jruby (1.0, 1.1) oraz zastosowałem kilka opcji kompilacji z jruby, by pokazać wam, która jest najlepsza. Do testów wykorzystano następujące interpretery/języki:

  • JRuby 1.0 i 1.1
  • PHP w wersji 4.4.7 i 5.2.5
  • Ruby w wersji 1.8.6 i 1.9

Algorytm w ruby (źródło )

def wariancje(s, n)
  if n == 0
    yield []
  else
    s.size.times do |i|
      wariancje(s, n-1) { |c| yield [s[i]] + c }
    end
  end
end
t = Time.now
s = "abcdefg"
size = s.size
i = 0
results = []
10.times do
  t = Time.now
  wariancje(s, size) do
    i += 1
  end
  tmp = Time.now - t
  results << tmp
  puts tmp
end
puts "\n#{results.min}, #{results.max}, #{size}, #{i}"

Algorytm w php

function wariancje($s, $n)
    {
      if ($n==0) return array('');
      $l = strlen($s);
      $ret = array();
      for ($i=0;$i<$l;$i++){
        foreach (wariancje($s, $n-1) as $c){
            $ret[] = $s[$i].$c;
        }
      }
      return $ret;
}
$s = "abcdefg";
$nelem = strlen($s);
$i = 0;
$results = array();
for ($j=0;$j<10;$j++){
  $t = time();
  $i += count(wariancje($s, $nelem));
  $tmp = time() - $t;
  $results[] = $tmp;
  echo $tmp . "\n";
}
echo min($results).":".max($results).":$nelem, $i";

Zestaw wyników dla 10 kolejnych prób wywołań metody z interpreterem jruby1.0 przedstawiono poniżej:



Jak widać czasy wykonania są bardzo duże a najlepszy wynik uzyskamy używając jruby1.0 z opcjami -J-server -J-Djruby.compile.frameless=true

Poniżej prześledźmy wykonanie naszego algorytmu dla pozostałych interpreterów/języków.









Prześledziwszy powyższe wykresy i tabele możemy wyciągnąć kilka wniosków:

  • Ruby 1.9 jest o 40% szybsze od Ruby 1.8.6
  • Użycie psyco z Pythonem 2.5 jest wolniejsze niż użycie samego Pythona
  • PHP5 jest znacznie szybsze od wersji PHP4 (o 30%)
  • JRuby1.1 jest najszybsze z opcjami -J-server -J-Djruby.compile.frameless=true

Prównajmy teraz wszystkie interpretery/języki o najlepszy wynikach uzyskanych w powyższych zestawieniach:


Powyższy wykres pokazuje, że jruby1.0 jest najmniej wydajnym z interpreterem. Ruby 1.9 wciąż jest wolniejszy od PHP5, choć różnica ta jest znacznie mniejsza niż przy wersji 1.8.6. Jruby z optymalnymi opcjami i Python 2.5 mają niemal identyczne czasy wykonania.

Proponuję jednak jeszcze bliżej przyjrzeć się tym dwóm interpreterom na poniższym wykresie.


Jak widać wykonanie algorytmu z użyciem Pythona jest wciąż szybsze niż z JRuby1.1. Jednak nie można nie zauważyć, że po pierwszym wykonaniu metody przez JRuby kolejne wykonania mają niemal identyczne czasy. Może to świadczyć o tym, że interpreter JRuby1.1 jest stabilniejszy od Pythona 2.5. Poza tym średnia wykonania 10 prób w Pythonie jest jedynie o 0,4 s szybsza niż z użyciem JRuby1.1. Warto zauważyć, że testy przeprowadzono na wersji RC, więc czasy te mogą być jeszcze lepsze dla JRuby1.1.

Zestawienie zbiorcze wyników testów:




Środowisko testowe:

  • CPU: 2GHz Intel Celeron (32bit)
  • RAM: 1GB
  • System: Ubuntu 7.10
  • Python, Ruby 1.8.6/1.9, JRuby 1.0 zainstalowane z pakietów

Zapraszam do dyskusji na forum