For or Foreach? PHP vs. Javascript, C++, Java, HipHop (update: HHVM v2)

Lessons learned:
  • Foreach is 4-5 times faster than For
  • Nested Foreach is 4-5 times faster than nested For
  • Foreach with key lookup is 2 times slower than Foreach without
  • C++ is 60 times faster than PHP running For/Foreach on Arrays
  • Javascript is 2-20 times slower than C++/Java running For on Arrays
  • HipHop is currently no alternative to C++
  • Using a better CPU makes the code 4-5 times faster

Here is a sample script, running on a 1.4 GHz machine with PHP 5.4.0:

// init arrays
$array = array();
for ($i=0; $i<50000; $i++) $array[] = $i*2;

$array2 = array();
for ($i=20000; $i<21000; $i++) $array2[] = $i*2;

// test1: foreach big-array (foreach small-array)
$start = microtime(true);
foreach ($array as $val) {
foreach ($array2 as $val2) if ($val == $val2) {}
}
echo (microtime(true)-$start)."\n";

// test1b: foreach big-array (foreach small-array)
$start = microtime(true);
foreach ($array as $val) {
foreach ($array2 as $val2) if ($val === $val2) {}
}
echo (microtime(true)-$start)."\n";

// test2: foreach small-array (foreach big-array)
$start = microtime(true);
foreach ($array2 as $val2) {
foreach ($array as $val) if ($val == $val2) {}
}
echo (microtime(true)-$start)."\n";

// test3: foreach big-array (foreach small-array) with key lookup
$start = microtime(true);
foreach ($array as $key=>$val) {
foreach ($array2 as $key2=>$val2) if ($array[$key] == $array2[$key2]) {}
}
echo (microtime(true)-$start)."\n";

// test4: foreach small-array (foreach big-array) with key lookup
$start = microtime(true);
foreach ($array2 as $key=>$val2) {
foreach ($array as $val) if ($array[$key] == $array2[$key2]) {}
}
echo (microtime(true)-$start)."\n";

// test5: for big-array (for small-array)
$start = microtime(true);
$count = count($array);
$count2 = count($array2);
for ($key=0; $key<$count; $key++) {
for ($key2=0; $key2<$count2; $key2++) if ($array[$key] == $array2[$key2]) {}
}
echo (microtime(true)-$start)."\n";

// test6: for small-array (for big-array)
$start = microtime(true);
$count = count($array);
$count2 = count($array2);
for ($key2=0; $key2<$count2; $key2++) {
for ($key=0; $key<$count; $key++) if ($array[$key] == $array2[$key2]) {}
}
echo (microtime(true)-$start)."\n";

$array = array();
for ($i=0; $i<1000000; $i++) $array[] = $i*2;

// test7: foreach big-array
$start = microtime(true);
foreach ($array as &$val) $val++;
echo (microtime(true)-$start)."\n";

// test8: for big-array
$start = microtime(true);
for ($key=0; $key<count($array); $key++) $array[$key]++;
echo (microtime(true)-$start)."\n";

// test8b: for big-array, doing count() outside the loop!
$start = microtime(true);
$count = count($array);
for ($key=0; $key<$count; $key++) $array[$key]++;
echo (microtime(true)-$start)."\n";


Here are some results from the HipHop compiler and HHVM (06/2012, Ubuntu 12.04, 64bit, AMD E-350):
php 5.3.10 [seconds] hphp [seconds] hhvm [seconds]
8.50 6.35 (-25%) 10.35 (+22%)
7.97 6.34 (-20%) 11.64 (+46%)
10.98 6.48 (-41%) 10.31 (-6%)
23.14 29.83 (+29%) 30.17 (+30%)
18.82 26.08 (+39%) 26.09 (+39%)
35.15 34.59 (-2%) 36.33 (+3%)
37.32 35.03 (-6%) 36.52 (-2%)
0.24 0.36 (+50%) 0.36 (+50%)
0.67 0.68 (+1%) 0.74 (+10%)

Here are some results from the HHVM v2.0.2 (05/2013, Ubuntu 12.04, 64bit, 3.4 GHz):
php 5.3.10 [seconds] hhvm [seconds]
1.97 1.90 (-3%)
1.86 1.91 (+3%)
2.27 1.92 (-16%)
5.04 5.68 (+13%)
4.70 5.31 (+13%)
4.21 5.50 (+31%)
4.59 5.56 (+21%)
0.05 0.06 (+20%)
0.17 0.13 (-23%)
0.08 0.07 (-13%)
Using HHVM instead of PHP does not give big improvements using one thread. Using a better CPU speeds up the code by a factor of 4-5.

With Javascript (node.js) you'll get similar values:
example.js (run: node example.js)

var array = [];
for (i=0; i<50000; i++) array.push(i*2);

var array2 = [];
for (i=20000; i<21000; i++) array2.push(i*2);

// js-test1: for big-array (for small array)
var start = new Date().getTime();
for (key=0; key<array.length; key++) {
for (key2=0; key2<array2.length; key2++) if (array[key] == array2[key2]) {}
}
console.log((new Date().getTime() - start) / 1000); // 2.6s, 0.8s

// js-test2: foreach big-array (foreach small array)
var start = new Date().getTime();
for (key in array) {
for (key2 in array2) if (array[key] == array2[key2]) {}
}
console.log((new Date().getTime() - start) / 1000); // 14.2s, 3.2s

var array = [];
for (i=0; i<1000000; i++) array.push(i*2);

// js-test3: for big-array
var start = new Date().getTime();
for (key=0; key<array.length; key++) array[key]++;
console.log((new Date().getTime() - start) / 1000); // 0.013s, 0.016s
tested with 1.6 GHz and 3.4 GHz

With C++ (gcc 4.6 win32) you'll also get similar values:
example.cpp (run: g++ -o example example.cpp && ./example)

#include <sys/time.h>
#include <stdio.h>
#include <vector>
using namespace std;

main() {
struct timeval start, end;

vector<int> array;
for(int i=0; i < 50000; i++) array.push_back(i*2);

vector<int> array2;
for(int i=20000; i < 21000; i++) array2.push_back(i*2);

gettimeofday(&start, NULL);
for (int key=0; key<array.size(); key++)
for (int key2=0; key2<array2.size(); key2++)
if (array[key] == array2[key2]) {}

gettimeofday(&end, NULL);
printf("%lf\n", (float)(end.tv_sec - start.tv_sec +
(end.tv_usec - start.tv_usec)/1000000.0)); // 1.04s, 0.30s, 0.0000s (-O3)

vector<int> array3;
for(int i=0; i < 1000000; i++) array3.push_back(i*2);

gettimeofday(&start, NULL);
for(int i=0; i < array3.size(); i++) array3[i]++;
gettimeofday(&end, NULL);
printf("%lf\n", (float)(end.tv_sec - start.tv_sec +
(end.tv_usec - start.tv_usec)/1000000.0)); // 0.013s, 0.005s, 0.0008 (-O3)
}
tested with 1.6 GHz and 3.4 GHz

And finally Java (Java 1.7 win64):

example.java (run: javac example.java && java example)

import java.util.ArrayList;

public class example {
public static void main(String[] args) throws Exception {

ArrayList<Integer> array = new ArrayList<Integer>();
for (int i = 0; i < 50000; i++) array.add(i*2);

ArrayList<Integer> array2 = new ArrayList<Integer>();
for (int i = 20000; i < 21000; i++) array2.add(i*2);

long start = System.currentTimeMillis();
for (int key = 0; key < array.size(); key++)
for (int key2 = 0; key2 < array2.size(); key2++)
if (array.get(key).equals(array2.get(key2))) {}
System.out.println((float) (System.currentTimeMillis() - start) / 1000);
// 0.12s (Vector: 10.6s), 0.04s

ArrayList<Integer> array3 = new ArrayList<Integer>();
for (int i = 0; i < 1000000; i++) array3.add(i*2);

start = System.currentTimeMillis();
for (int i = 0; i < array3.size(); i++) array3.set(i, array3.get(i)+1);
System.out.println((float)(System.currentTimeMillis() - start) / 1000);
// 0.04s (Vector: 0.17s), 0.04s
}
}
tested with 1.6 GHz and 3.4 GHz

Comments

Popular posts from this blog

How to show only month and year fields in android Date-picker?

How to construct a B+ tree with example

Conflict Serializability in database