J'essaie de comparer un algo de quicksorting contre Enum.sort
. Je reçois des résultats très différents de benchfella
et benchwarmer
.Elixir Benchfella & Benchwarmer ont des résultats radicalement différents
Résumé:
Benchfella Benchwarmer
Enum.sort 8920.47 µs/op 2418767.00 μs/op
QuickSort 16660.45 µs/op 15745.04 μs/op
Détails:
Voici ce que je suis l'analyse comparative:
defmodule Thing do
defstruct [:key]
end
defmodule QuickSort do
def qsort([]), do: []
def qsort([pivot | rest]) do
{left, right} = Enum.partition(rest, fn(x) -> x.key < pivot.key end)
qsort(left) ++ [pivot] ++ qsort(right)
end
end
defmodule Bench do
use Benchfella
Benchfella.start
bench "QuickSort", [list: gen()] do
QuickSort.qsort(list)
end
bench "Enum.sort", [list: gen()] do
Enum.sort(list, fn(x, y) -> x.key > y.key end)
end
def gen, do: for _ <- 1..10000, do: %Thing{key: :rand.uniform}
# Tests
list = for _ <- 1..10000, do: %Thing{key: :rand.uniform}
sorted = Enum.sort_by(list, &(&1.key))
true = sorted == QuickSort.qsort(list)
end
est ici la sortie de Benchfella
:
$ mix bench
Settings:
duration: 1.0 s
## Bench
[20:57:40] 1/2: Enum.sort
[20:57:43] 2/2: QuickSort
Finished in 4.71 seconds
## Bench
benchmark iterations average time
Enum.sort 200 8920.47 µs/op
QuickSort 100 16660.45 µs/op
est ici la sortie de Benchwarmer
:
$ iex -S mix
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> list = Bench.gen
[%Thing{key: 0.29976857621751096}, %Thing{key: 0.42956956935048163},
%Thing{key: 0.8682735084348573}, %Thing{key: 0.13149039866062429},
%Thing{key: 0.5315758481143932}, %Thing{...}, ...]
iex(2)> Benchwarmer.benchmark fn -> QuickSort.qsort list end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
1.9 sec 127 iterations 15745.04 μs/op
[%Benchwarmer.Results{args: [], duration: 1999619,
function: #Function<20.52032458/0 in :erl_eval.expr/5>, n: 127, prev_n: 64}]
iex(3)> Benchwarmer.benchmark fn -> Enum.sort(list, fn(x, y) -> x.key > y.key end) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
2.4 sec 1 iterations 2418767.0 μs/op
[%Benchwarmer.Results{args: [], duration: 2418767,
function: #Function<20.52032458/0 in :erl_eval.expr/5>, n: 1, prev_n: 1}]
On dirait qu'Erlang est incapable d'effectuer une optimisation pour 'fn' déclaré directement dans le REPL (en dehors d'un module). Je vois des résultats similaires à Benchfella si je mets le code Benchwarmer dans un module puis je l'appelle et je peux aussi reproduire le timing de ~ 2.5 secondes avec ': timer.tc fn -> Enum.sort (list, fn (x, y) -> x.key
Dogbert
Vous comparez différents cadres _et_ structure de code différente _ et_ AFAICT même des données différentes. Veuillez retravailler vos exemples afin qu'une seule chose soit différente, sinon il est impossible de faire une comparaison. – cdegroot
Je ne suis pas sûr qu'il soit juste de me donner un -1 pour cette question. Je demande pourquoi «différents cadres et structure de code différente» donnent des résultats différents et auxquels il faut faire confiance. Je pense que c'est une question très valable et que les débutants dans 'Elixir' trouveraient utile. – jdesilvio