Seite 1 von 1

rechenzeitunterschiede bei verschachtelten funktionen

Verfasst: Montag 28. Mai 2007, 12:56
von kommando_pimperlepim
noch eine frage zur performance:
habe mittels time.clock (für exakte zeitmessungen unter windows, siehe http://www.python-forum.de/topic-10213. ... eitmessung) zwei routinen verglichen, die die gleiche berechnung ausführen. nur einmal über zwei verschachtelte funktionen und einmal über eine einzige funktion

Code: Alles auswählen

from time import *
from numpy import *

def f1(x):
    return x+1
def f2(x):
    return f1(x)+1
def f3(x):
    return x+1+1

a=linspace(1.0,20.0,4000000)

t1=clock()
b=f2(a)                   b=f3(a)
t2=clock()
print t2-t1
# liefert 2.42571276517   # liefert 3.17065129786
wie kann man sich erklären, dass die berechnung mit dem zusätzlichen schritt über die zwischenfunktion schneller erfolgt?

Verfasst: Montag 28. Mai 2007, 17:00
von Leonidas
In ``f2`` muss der Name ``f1`` erst nachgeschaut werden, danach muss die Funktion ausgeführt werden, die einen Rückgabewert bietet und dann wird in ``f2`` dieser Wert um 1 erhöht.

``f3`` hingegen nimmt den an ``x`` gebundenen Wert und erhöht ihn sofort um 2.

``f2`` macht einen Umweg über ``f1``, ``f3`` geht direkt. Das ist der Unterschied.

Verfasst: Montag 28. Mai 2007, 19:56
von thelittlebug
Ja, aber ich glaube er wollte wissen warum der "Umständlichere Weg" schneller ist ;)

lgherby

Verfasst: Montag 28. Mai 2007, 20:03
von Leonidas
thelittlebug hat geschrieben:Ja, aber ich glaube er wollte wissen warum der "Umständlichere Weg" schneller ist ;)
Definiere "umständlich". Ich finde ja ``f3`` weniger umständlich. Eine andere Sache ist die Testmethode. Man sollte mit ``timeit`` und einer größeren Zahl von Iterationen testen, sonst kommt einem gegebenfalls die Streuung in die Quäre.

Verfasst: Montag 28. Mai 2007, 20:06
von thelittlebug
Das ist ja das was ich damit meine:

f3 ist weniger umständlich aber trotzdem langsamer ;)

lgherby

Verfasst: Montag 28. Mai 2007, 21:16
von Leonidas
thelittlebug hat geschrieben:f3 ist weniger umständlich aber trotzdem langsamer ;)
Ah, ok - hab falsch geschaut :oops:. Meine Erklärung ist dadurch aber nicht falsch. Den Unterschied würde ich auf die Streuung schieben. Könnte jemand das mal mit ``timeit`` testen und viele Iterationen machen? Ansonsten sind diese Werte bei einmaliger Messung nicht repräsentativ.

Verfasst: Montag 28. Mai 2007, 21:43
von Sr4l
Also bei mir sind beide Wege 'gleich schnell' beide Funktionen schwanken zwischen 0.09 und 0.12. Ich habe Ubuntu 7.04 mit Python 2.5.1 auf einem Intel Centrino @ 1,73 Ghz. Auch bei je 100gestoppten durchläufen liegen beide Werte noch zusammen bei etwa 10.4 Sekunden.

Ich weiß nicht warum das bei dir 2.4 und 3.1 Sekunden gedauert hat.
Mein Laptop hatte 800Mhz oder 1730 Mhz eiegtlich müsste jeder schneller sein.
Gerade Windows Nutzer bei mir war Python mit Intel Compiler immer schneller als Python mit GCC.

PS: Habe den Code 1:1 kopiert.

Verfasst: Montag 28. Mai 2007, 22:56
von birkenfeld
Schon mal rein prinzipiell *kann* f3 nicht langsamer als f2 sein.

Laufen bei dir (@OP) vielleicht irgendwelche Hintergrundprozesse, die CPU brauchen? Oder Speedstepping?

Verfasst: Montag 28. Mai 2007, 23:07
von Leonidas
Also, hier der Benchmark-Code: #1534 (Wieso wird eigentlich usec/pass falsch angezeigt? Der Code ist quasi aus der Dokumentation von ``timeit`` übernommen)

Die Benchmark-Ergebnisse (habe ``numpy`` mal schnell selbst kompiliert, daher kann es sein, dass der da nicht die performantesten Libraries genommen hat):

Code: Alles auswählen

$ python2.5 numpymark.py
0.26 usec/pass
0.22 usec/pass
$ python2.5 numpymark.py
22.22 usec/pass
20.05 usec/pass
$ python2.5 numpymark.py
2.09 usec/pass
1.77 usec/pass
$ python2.5 numpymark.py
20.36 usec/pass
18.86 usec/pass
$ python2.5 numpymark.py
2027.87 usec/pass for composed function
2198.69 usec/pass for simple function
Ich habe am loops-Wert immer ein wenig gedreht (zuletzt war es 1000) und *meistens* ist die erste Methode langsamer. Das das beim letzten Versuch umgekehrt ist, liegt vermutlich daran, dass sich einige Hintergrundprozesse eingeschaltet haben.

Damit es fair ist, müsste man eigentlich beide Vorgehensweisen gleichzeitig ausführen lassen, also mit Threads. Benchmarken ist gar icht so einfach wie man denken könnte... Ich werde es noch mit einem anderen Computer ausprobieren, aber der ist immer noch beschäftigt ``numpy`` zu kompilieren, vielleicht kann ich den Benchmark über Nacht laufen lassen.

Verfasst: Mittwoch 30. Mai 2007, 19:24
von Joghurt
Auf jeden Fall ist dieser Thread ein schönes Beispiel dafür, warum man immer erst am Ende optimieren sollte, und dann auch nur da, wo das Profiling einen Bottleneck zeigt; die zeigen sich nämlich oft an den seltsamsten Stellen.

Verfasst: Mittwoch 30. Mai 2007, 19:26
von Grossmeister_C
Soll ja auch Leute geben für die das optimieren der eigentliche Sport ist ^^

Verfasst: Mittwoch 30. Mai 2007, 23:26
von Leonidas
Grossmeister_C hat geschrieben:Soll ja auch Leute geben für die das optimieren der eigentliche Sport ist ^^
Die sind aber in der Regel unter Python schlecht aufgehoben. Ich habe mal Primzahlberechnung optimiert und der Code der am schluss rausgekommen ist, war zwar definitiv schneller, aber er sah nicht mehr so schön aus. Fand ich also aus Python-Programmierer-Sicht eher unästhetisch.