Playing with Ruby 1.8, Ruby 1.9 and PHP
Today, I wanted to give a try to the latest Ruby 1.9 snapshot.
After disabling the set_thread_priority() call, it compiles and installs fine on OpenBSD. My test host is an Athlon 64 3400, running OpenBSD-current/amd64.
Before all, I wanted to benchmark it against Ruby 1.8.
Here's a simple and stupid test script I wrote, just to have something that iterates over arrays, calls methods, use a class-scoped counter, and does common tests:
class String
@@counter = 0
def testfunc2
array = self.split
str = ""
array.each do |word|
str << word unless word.empty? or @@counter < 0
@@counter += 1
end
end
def testfunc!
self << "abc "
testfunc2.join("-")
end
end
str = "initial string"
5000.times { str.testfunc! }
Very simple. It takes a string, it adds "abc " to that string, it transforms it into an array of words, it iterates over every word and add each word to a new string with two useless tests by the way, it increments a class-wide counter, it returns the array of words, then all these words are joined by a dash. That happens 5000 times.
Here we go for the bench:
- Ruby 1.8: 0m23.06s
- Ruby 1.9: 0m11.65s
That's pretty cool. Ruby 1.9 is more than twice as fast as Ruby 1.8 here!
Out of curiosity, I wanted to translate that simple example to PHP in order to see how it would compare. Unfortunately, adding methods to strings is something PHP is unable to do. PHP doesn't let you extend strings, numerics, nor functions. So in order to do something similar to the previous test scripts, we have to reinvent the wheel, we have to invent a "String" class. Woah. And we can't even use that class as a string, because unlike any object-oriented language from the past 20 years, PHP is not even able to overload operators. It's why we have to invent a method ("set_value") just to set the content of the string. Ok, here we go for the PHP version of the above script :
class String {
var $str;
protected static $counter = 0;
public function set_value($str) {
$this->str = $str;
}
public function __construct($str) {
$this->set_value($str);
}
public function __toString() {
return $this->str;
}
public function testfunc2() {
$array = split(' ', $this);
$str = "";
foreach ($array as $word) {
if (!(empty($word) || self::$counter < 0)) {
$str .= $word;
}
self::$counter++;
}
return $array;
}
public function testfunc() {
$this->set_value($this . "abc ");
implode($this->testfunc2(), "-");
}
}
$str = new String("initial string");
$i = 5000;
do {
$str->testfunc();
} while (--$i !== 0);
All those "$this->" and "self::" are boring and useless, they don't bring anything but ugly source code. PHP loves to annoy programmers by forcing them to write symbols like "$", "_", "->" and "::" everywhere. You have to write them over and over again, for everything you need in the current object, or you will get that wonderful error: "syntax error, unexpected TPAAMAYIMNEKUDOTAYIM".
Okay, let's benchmark the PHP script:
- Ruby 1.8: 0m23.06s
- Ruby 1.9: 0m11.65s
- PHP 5.2.3: 1m36.46s
Yes, that's one minute and 36 seconds. You got the codes, try them yourself. The PHP script is not only ugly, it's also dog slow.
Please stop calling PHP a serious object-oriented language and please stop benchmarking languages over a function that computes prime numbers.
Comments
-
I don’t know if it really mimics the ruby code as I don’t understand that language nor PHP, but here is a try in Python:
class TestPy(object): def init(self, string): self.string = string self.counter = 0
def testfunc(self): self.string += 'abc ' '-'.join(self.testfunc2())def testfunc2(self): array = self.string.split() str = '' for word in array: if not str or self.counter < 0: str += word self.counter += 1 return arraystr = “initial string” a = TestPy(str) for x in range (0,4999): a.testfunc()
$ time python jeditest.py
real 0m8.903s user 0m8.744s sys 0m0.140s
$ time ruby test.rb
real 0m17.594s user 0m17.318s sys 0m0.216s
$ ruby -v ruby 1.8.2 (2004-12-25) [universal-darwin8.0]
$ python Python 2.4.4 (#1, Oct 18 2006, 10:34:39) [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
On iMac 24, 2.16GHz Intel Core 2 Duo.
AkH
-
http://kdl.nobugware.com/post/2007/07/08/Comparing-Ruby-vs-Python-vs-PHP
;)
-
You forgot to backslash your underscores in set thread priority – turned it to italics :)
-
Hello Akh!
How are you? Nice to hear from you!
Your Python code doesn’t behave as those above.
if not str or self.counter < 0:
should probably be:
if not (not word or self.counter < 0):
without that change, the length of the string doesn’t change.
Also, “counter” should be a class-variable.
Anyway, just like Ruby, Python is a language that was designed from scratch for object-oriented programming. It’s not a big surprise that it performs well for that kind of task.
Benchmarks of languages always compare useless stuff like functions that compute fibonacci sequences, prime numbers, etc. Holly crap. How many times did you intensively compute fibonacci sequences in real applications?
That little benchmark was initially only designed to compare Ruby 1.8 with Ruby 1.9. Translations to other languages is not obvious. But since this is an interesting subjecct, I’ll try to work on some other, easy to translate, object-oriented benchmarks.
Thanks a lot for your contribution, Akh.
-
I may be wrong but I think that the PHP bench is very slow because you used the split() function instead of the explode() one. split() use posix regular expression while explode doesn’t and I suppose that your Ruby bench didn’t use regular expression.
When I tested your PHP bench, I’ve got : time /usr/bin/php test-jedi.php real 3m23.237s user 3m21.960s sys 0m1.090s
When I replace split() with explode(), I’ve got : time /usr/bin/php test-jedi.php real 1m15.418s user 1m14.320s sys 0m1.080s
I think it’s still slower than Ruby (1.8 and 1.9) but less slower.