2016-01-09 25 views
12

zauważyłem, że array.min wydaje się powolny, więc zrobiłem ten test przed moim naiwnym realizacji:Dlaczego tablica.min jest taka powolna?

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 

Efekty:

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) 

Jestem w szoku. W jaki sposób moja własna implementacja blokowania poprzez each może pokonać wbudowane? I pokonać to tak bardzo?

Czy jestem w jakiś sposób w błędzie? Czy to jest jakoś normalne? Jestem zmieszany.


wersja

My Ruby, uruchomiony w systemie Windows 8.1 PRO:

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

Moje wyniki są całkiem różne https://gist.github.com/weppos/3411eafc2c52e69ec751 –

+0

Więc są równie szybkie jak dla ciebie. Nadal mnie zaskakuje. Jaką masz wersję? Mam 2.2.2p95, zaktualizuję teraz do wersji 2.3 i przetestuję ponownie. –

+0

Oczywiście 2.2.3. Zrobiłem to teraz, ale wciąż obserwuję to samo. –

Odpowiedz

2

Zobacz implementację Enumerable#min. Może w końcu użyć each, aby zapętlić elementy i uzyskać element min, ale przed tym robi dodatkowe sprawdzenie, czy musi zwrócić więcej niż jeden element, czy też musi porównać elementy za pomocą przejętego bloku. W twoim przypadku elementy zostaną porównane za pomocą funkcji min_i i podejrzewam, że stąd bierze się różnica prędkości - ta funkcja będzie wolniejsza niż porównywanie dwóch liczb.

Nie ma dodatkowej optymalizacji dla tablic, wszystkie wyliczenia są wykonywane w ten sam sposób.

+0

Dzięki. Wciąż bym się spodziewał, że prawdopodobnie kompilacja C będzie znacznie szybsza niż moja prawdopodobnie interpretowała Ruby. Ale patrząc na tę funkcję 'min_i' widzę' OPTIMIZED_CMP (i, memo-> min, memo) <0', i jeśli zmienię własną implementację, aby użyć 'min = n if (n <=> min) <0', to to przynajmniej staje się * wolniejsze * niż wbudowane (około 8% w moim teście). Chyba zostawię to i po prostu opłakuję, że jeśli chcę tego szybko, muszę to zrobić sam z moją "długą" drogą ... –

1

To nawet szybciej, jeśli używasz:

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 

UWAGA

wiem, że to nie jest odpowiedź, ale pomyślałem, że warto się podzielić i umieścić ten kod w komentarzu byłeś wyjątkowo brzydki.