2016-01-09 27 views
12

Ho notato che array.min sembra lento, così ho fatto questo test contro la mia propria implementazione ingenuo:Perché array.min è così lento?

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 

I risultati:

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) 

Sono scioccato. Come può la mia implementazione eseguire un blocco tramite each battere il built-in? E battere così tanto?

Sono in qualche modo in errore? O è in qualche modo normale? Non ho capito bene.


versione

mio Ruby, in esecuzione su Windows 8.1 Pro:

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

I miei risultati sono abbastanza diversi https://gist.github.com/weppos/3411eafc2c52e69ec751 –

+0

Quindi sono ugualmente veloci per te. Mi sorprende ancora. Quale versione hai? Ho 2.2.2p95, aggiornerò a 2.3 ora e riproverò. –

+0

Significa 2.2.3 ovviamente. Fatto questo ora, ma osservo ancora la stessa cosa. –

risposta

2

Dai un'occhiata all'implementazione di Enumerable#min. Potrebbe utilizzare lo each per passare in ciclo gli elementi e ottenere l'elemento min, ma prima di eseguire qualche controllo aggiuntivo per vedere se è necessario restituire più di un elemento o se deve confrontare gli elementi tramite un blocco passato. Nel tuo caso gli elementi saranno confrontati tramite la funzione min_i, e ho il sospetto che sia da lì che viene la differenza di velocità - quella funzione sarà più lenta rispetto al semplice confronto di due numeri.

Non c'è ottimizzazione aggiuntiva per gli array, tutti gli enumerabili sono attraversati allo stesso modo.

+0

Grazie. Mi sarei comunque aspettato che C fosse presumibilmente compilato molto più velocemente di quanto presumibilmente interpretasse Ruby. Ma osservando la funzione 'min_i' vedo' OPTIMIZED_CMP (i, memo-> min, memo) <0', e se cambio la mia implementazione per usare 'min = n if (n <=> min) <0', quindi almeno diventa * più lento * rispetto al built-in (circa l'8% nel mio test). Immagino che lascerò questo e piangerò che se lo voglio veloce, devo farlo da solo con il mio modo "lungo" ... –

1

E 'ancora più veloce se si utilizza:

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 

NOTA

So che questo non è una risposta, ma ho pensato che valesse la pena condividere e inserire questo codice in un commento woul Sono stato estremamente brutto.