2016-05-31 14 views
1

Ausführungszeit für diesen Code ist etwa 1 Sekunde:Eine Schleife mit vielen Iterationen macht Ausführung unglaublich langsam

start_time = Time.now 

prev = 1 
(1..1000).each do |i| 
    (1..10000).each do |j| 
    result = j * prev 
    result = result + prev 
    result = result - prev 
    result = result/prev 
    prev = j 
    end 
end 

end_time = Time.now 
printf('%f sec', end_time - start_time) 

Aber wenn ich eine Schleife mit 10000000 Iterationen verwenden (anstelle von 2-Schleifen, 1000 und 10000 Iterationen geschrieben oben), es wurde viel langsamer (etwa 4,5 Sekunden):

start_time = Time.now 

prev = 1 
(1..10000000).each do |j| 
    result = j * prev 
    result = result + prev 
    result = result - prev 
    result = result/prev 
    prev = j 
end 

end_time = Time.now 
printf('%f sec', end_time - start_time) 

Warum passiert es? Die Gesamtzahl der Iterationen ist immer noch gleich.

+1

Versuchen jeweils Werte von 'result' zu untersuchen. Ich denke '10_000_000 * 9_999_999' ist größer als' 10_000 * 9_999'. –

+1

Ich habe 1.35sec für die erste und 1.24sec für den zweiten Code. Die Variable'Ergebnis' wächst nicht übermäßig, weil sie jedesmal neu gesetzt wird. –

+0

Also, Iteration des ersten Codes ist im Grunde 1,35 Sekunden und 1,24 Sekunden für die Sekunde? Ungerade. Versuchen Sie, die Ausführung bei kleineren Blöcken zu protokollieren, z. B. alle 20%. Die Gesamtbelastung sollte sich mit einer einfachen Überprüfung gleichmäßig erhöhen, so dass der Test nicht sichtbar beeinflusst wird. –

Antwort

2

Das zweite Beispiel verarbeitet viel größere Zahlen als die erste (wie @Sergii K oben kommentiert). Es ist möglich, dass der zweite Beispielcode das maximale Fixnum-Limit auf Ihrem System erreicht. Bei einem 32-Bit-System ist maximum signed integer2**(32-1) - 1 = 2147483647, was viel weniger ist als das maximale Produkt j * prev im zweiten Beispiel (im Gegensatz zu max-Produkten im ersten Beispiel). In einer Situation wie diesem muss Ruby die intern zu Bignums konvertieren, weshalb der zweite Beispielcode möglicherweise langsamer als der erste ist.

Auf einem 64-Bit-System würde ich erwarten, dass beide Samples ungefähr zur gleichen Zeit laufen, weil die größten Integer niemals das Fixnum-Limit erreichen werden. Deshalb haben vielleicht die meisten anderen Kommentatoren keinen großen Unterschied in den Zeiten gesehen.

aktualisieren: Wenn die max Fixnum Zahl nur 1073741823 ist, wie oben durch die OP kommentiert, dann muss es bedeuten, dass, während das Betriebssystem selbst ist 64-Bit und vielleicht der installierte Rubin ist auch ein 64-Bit-Rubin, Es verwendet immer noch nur 4 Bytes, um Fixnum-Nummern zu speichern (statt 8 in echten 64-Bit-Rubinen). Der Max-Integer-Wert ist viel weniger als in dem zweiten Beispiel erforderlich, so dass er tatsächlich die höheren Zahlen in Bignums umwandeln muss, und genau hier kommt die Langsamkeit des zweiten Samples her.

Sie können dies selbst überprüfen, wenn Sie vergleichen:

(2**(0.size * 8 -2) -1).class  # => Fixnum vs: 
(2**(0.size * 8 -2) -1 + 1).class # => should be Bignum