Suivez moi sur GitHub

Guirec Corbel

Mon blog

Benchmark : go vs crystal vs ruby

| Comments

Crystal est un nouveau venu dans le monde des langages de programmation. Le but de ce langage est d’avoir une synthaxe similaire à Ruby tout en ayant les performances du C. Dans cet article, je vous propose de faire une comparaison entre le langage populaire et rapide, Go, ce jeune langage, Crystal, et son inspiration, Ruby.

Resultats

Sans plus attendre, voici les résultats en image :

Benchmark Go vs Crystal vs Ruby

Comme Ruby a des performances bien en dessous de Go et Crystal, voici le même graphique en le retirant :

Benchmark Go vs Crystal

Plus de détails sur les tests par la suite.

Fibonacci

Comme premier programme, j’ai choisi de faire un benchmark avec un programme comptant selon la suite de Fibonacci. N’étant pas un développeur Go, j’ai trouvé le code ici et l’ai modifié pour faire ce que je souhaite, c’est-à-dire m’afficher uniquement le résultat selon la valeur passée en paramètre.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "math/big"
import "fmt"

func fibonacci(n int) *big.Int {
    first, second := 0, 1
    for i := 0; i < n; i++ {
        first.Add(first, second)
        first, second = second, first
    }
    return second
}

func main() {
    fmt.Println(Fibonacci(40))
}

Voici une implémentation similaire en Ruby :

1
2
3
4
5
6
7
8
9
def fib(n)
  first, second = 0, 1
  n.times do
    first = first + second
    first, second = second, first
  end
  return second
end
puts fib(40)

Et la voici avec Crystal :

1
2
3
4
5
6
7
8
9
def fib(n)
  first, second = 0, 1
  n.times do
    first = first + second
    first, second = second, first
  end
  return second
end
puts fib(40)

Ne cherchez pas de différence entre Ruby et Crystal, il n’y en a pas. Dans ce cas, Ruby et Crystal sont totalement similaires.

Voici les résultats :

1
2
3
4
5
go build fib.go && time ./fib

real    0m0.001s
user    0m0.000s
sys     0m0.001s
1
2
3
4
5
time ruby fib.rb

real    0m0.035s
user    0m0.029s
sys     0m0.006s
1
2
3
4
5
crystal build --release fib.cr && time ./fib

real    0m0.003s
user    0m0.001s
sys     0m0.002s

On peut voir que Go gagne suivi de Crystal et de Ruby. Cependant, dans ce test, les temps d’exécution sont tellement rapides que beaucoup d’autres facteurs peuvent entrer en jeu dans le temps d’exécution.

Fibonacci BigInt

Pour poursuivre les tests, j’ai voulu augmenter la valeur à calculer. Malheureusement, pour Go et Crystal, la taille des entiers n’est pas suffisante. Il a donc été nécessaire de modifier le code pour utiliser des BigInt.

Voici le code Go modifié :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "math/big"

func fibonacci(n int) *big.Int {
    first, second := big.NewInt(0), big.NewInt(1)
    for i := 0; i < n; i++ {
        first.Add(first, second)
        first, second = second, first
    }
    return second
}

func main() {
    Fibonacci(100000)
}

Et la même chose avec Crystal :

1
2
3
4
5
6
7
8
9
10
11
require "big_int"

def fib(n)
  first, second = 0.to_big_i, 1.to_big_i
  n.times do
    first = first + second
    first, second = second, first
  end
  return second
end
fib(1000000)

Et voici les résutats :

1
2
3
4
5
go build fib.go && time ./fib

real    0m3.831s
user    0m3.826s
sys     0m0.009s
1
2
3
4
5
time ruby fib.rb

real    0m11.188s
user    0m9.873s
sys     0m1.290s
1
2
3
4
5
crystal build --release fib.cr && time ./fib

real    0m19.414s
user    0m29.527s
sys     0m4.969s

Le résultat est un peu décevant. L’utilisation du BigInt en Crystal est lente. La raison de cette lenteur viens du faire que Crystal utilise GMP qui est manifestement plus lent que l’implémentation de Go. Vous pouvez voir une discussion sur la lenteur de Crystal ici.

Autres Benchmarks

Je n’ai pas voulu me laisser abattre au premier test et j’ai décidé d’en faire d’autres. J’ai trouvé ce projet. Malheureusement, les codes proposés ne fonctionnent pas toujours avec les dernières versions des langages. Je me suis contenté de faire une comparaison avec les scripts fonctionnant sans modifications.

Brainfuck

1
2
3
4
5
6
go build brainfuck.go && time ./brainfuck bench.b
ZYXWVUTSRQPONMLKJIHGFEDCBA

real    0m6.510s
user    0m6.514s
sys     0m0.011s
1
2
3
4
5
6
time ruby brainfuck.rb bench.b
ZYXWVUTSRQPONMLKJIHGFEDCBA

real    3m5.364s
user    3m4.724s
sys     0m0.586s
1
2
3
4
5
6
crystal build --release brainfuck.cr  && time ./brainfuck bench.b
ZYXWVUTSRQPONMLKJIHGFEDCBA

real    0m5.930s
user    0m5.924s
sys     0m0.005s

Havlak

1
2
3
4
5
6
7
8
9
10
11
12
13
14
go build havlak.go && time ./havlak
Welcome to LoopTesterApp, Go edition
Constructing Simple CFG...
15000 dummy loops
Constructing CFG...
Performing Loop Recognition
1 Iteration
Another 50 iterations...
..................................................
Found 76001 loops (including artificial root node) (3800050)

real    0m32.058s
user    0m53.207s
sys     0m1.433s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
crystal build --release havlak.cr  && time ./havlak
Welcome to LoopTesterApp, Crystal edition
Constructing Simple CFG...
15000 dummy loops
Constructing CFG...
Performing Loop Recognition
1 Iteration
Another 50 iterations...
..................................................
Found 76002 loops (including artificial root node) (3800100)

real    0m14.083s
user    0m20.487s
sys     0m0.186s

On peut voir que Crystal est deux fois plus rapide que Go. J’émets une petite réserve sur le code fait avec Crystal. Celui-ci a été fait à partir de celui fait en Python et ne respect pas la “Crystal way”.

Matmul

1
2
3
4
5
6
go build matmul.go && time ./matmul 1500
-143.500167

real    0m3.189s
user    0m3.156s
sys     0m0.049s
1
2
3
4
5
6
time ruby matmul.rb 1500
-143.5001666666568

real    4m51.220s
user    4m50.842s
sys     0m0.300s
1
2
3
4
5
6
crystal build --release matmul.cr  && time ./matmul 1500
-143.5

real    0m3.868s
user    0m3.879s
sys     0m0.024s

Encore une fois, Ruby est en retrait. Les performances entre Go et Crystal sont comparables bien que Go est légèrement plus rapide.

Conclusion

Pour conclure, je dirais que Crystal, bien que très jeune, offre des performances intéressantes. Le futur nous dira s’il s’agit d’un projet éphémère ou s’il fera ses preuves.

J’espère pouvoir faire d’autres tests sur Crystal très bientôt. Je pense essayer de faire une API. Suivez-moi sur Twitter pour rester au courant.

Comments