2016-01-09 10 views
12

Ich bemerkte, dass array.min langsam scheint, so habe ich diesen Test gegen meine eigene naive Umsetzung:Warum ist array.min so langsam?

require 'benchmark' 
array = (1..100000).to_a.shuffle 

Benchmark.bmbm(5) do |x| 
    x.report("lib:") { 99.times { min = array.min } } 
    x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n < min } } } 
end 

Die Ergebnisse:

Rehearsal ----------------------------------------- 
lib: 1.531000 0.000000 1.531000 ( 1.538159) 
own: 1.094000 0.016000 1.110000 ( 1.102130) 
-------------------------------- total: 2.641000sec 

      user  system  total  real 
lib: 1.500000 0.000000 1.500000 ( 1.515249) 
own: 1.125000 0.000000 1.125000 ( 1.145894) 

Ich bin schockiert. Wie kann meine eigene Implementierung einen Block über each schlagen die eingebaute? Und schlage es so sehr?

Bin ich irgendwie falsch? Oder ist das irgendwie normal? Ich bin verwirrt.


Meine Ruby-Version, die unter Windows 8.1 Pro:

C:\>ruby --version 
ruby 2.2.3p173 (2015-08-18 revision 51636) [i386-mingw32] 
+0

Meine Ergebnisse sind ziemlich unterschiedlich https://gist.github.com/weppos/3411eafc2c52e69ec751 –

+0

So sind sie etwa gleich schnell für Sie. Überrascht mich immer noch. Welche Version hast du? Ich habe 2.2.2p95, werde jetzt auf 2.3 updaten und nochmal testen. –

+0

Gemeint sind 2.2.3 natürlich. Habe ich jetzt, aber ich beobachte immer noch das Gleiche. –

Antwort

2

Werfen Sie einen Blick auf die Implementierung von Enumerable#min. Es könnte each schliesslich verwenden, um die Elemente durchzulaufen und das min-Element zu erhalten, aber vorher prüft es, ob es mehr als ein Element zurückgeben muss, oder ob es die Elemente über einen übergebenen Block vergleichen muss. In Ihrem Fall werden die Elemente über min_i Funktion verglichen, und ich vermute, dass das ist, wo die Geschwindigkeitsdifferenz herkommt - diese Funktion wird langsamer sein als einfach zwei Zahlen zu vergleichen.

Es gibt keine zusätzliche Optimierung für Arrays, alle Enumerables werden auf die gleiche Weise durchlaufen.

+0

Danke. Ich hätte immer noch erwartet, dass kompiliertes C viel schneller ist als mein vermutlich interpretierter Ruby. Aber wenn ich diese "min_i" -Funktion betrachte, sehe ich 'OPTIMIZED_CMP (i, memo-> min, memo) <0 ', und wenn ich meine eigene Implementierung so ändere, dass' min = n if (n <=> min) <0 'verwendet wird, dann es wird mindestens * langsamer * als das eingebaute (ca. 8% in meinem Test). Ich denke, ich werde es dabei belassen und nur trauern, wenn ich es schnell will, muss ich es selbst auf meine "lange" Art machen ... –

1

Es ist sogar schneller, wenn Sie verwenden:

def my_min(ary) 
    the_min = ary[0] 
    i = 1 
    len = ary.length 
    while i < len 
    the_min = ary[i] if ary[i] < the_min 
    i += 1 
    end 
    the_min 
end 

HINWEIS

ich weiß, ist dies nicht eine Antwort, aber ich dachte, es wäre es wert, geteilt zu werden und diesen Code in einen Kommentar zu schreiben Ich war sehr hässlich.