Wie kann ich meinen Python-Code schneller machen?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Du hängst dauernd Sachen an Arrays an. Das kostet je nach Implementation Zeit; vielleicht Speicher vorreservieren und dann über einen Index ansprechen.

Du verwendest "teure" Berechnungen - einen Arcustangens zu berechnen dauert an sich schon recht lange.

Ach ja: Und mach zeitkritische Sachen vielleicht in einer Programmiersprache, die auf Schnelligkeit getrimmt ist, z.B C oder C++.

Woher ich das weiß:Hobby – Hobby seit meiner Jugend

Croover 
Fragesteller
 19.12.2021, 13:19

Wie kann ich den ersten Vorschlag umsetzen? Ich bin nicht sehr erfahren, was so etwas angeht.

Übrigens ist der Arcustangens leider nötig, da ich alle möglichen Werte in ein Intervall von 0 bis 1 quetschen muss. Alternativ ginge auch der Tangens Hyperbolicus, aber der geht mir zu schnell an -1 und 1 heran.

0
ShimaG  19.12.2021, 13:26
@Croover

Ich mache eigentlich kein Python, daher weiß ich nicht, wie das Vor-Reservieren von Speicher funktioniert.

Noch ein paar andere Tips:

  • Ich würde vielleicht auch "x**2" durch "x*x" ersetzen. Das erste wird vielleicht auf eine Exponentialfunktion gebracht, das zweite ist eine schnellere Multiplikation.
  • Wenn dir der Tangens Hyperbolicus zu schnell an +/-1 geht, dann skaliere doch einfach das Argument.
  • Ich würde die "teuren" Funktionen mal durch "billige" (z.B. den Wert 0) ersetzen, um erstmal überhaupt herauszufinden, wo das Programm die Zeit verbringt.
1
KarlRanseierIII  19.12.2021, 16:00
@ShimaG

** wird auf pow abgebildet, welche für integrale Exponenten mul nutzt.

Sollte also kein Beinbruch sein:

>>> timeit.timeit("1.5*1.5",number=10000000)
0.2979741969611496
>>> timeit.timeit("1.5**2",number=10000000)
0.298094579949975

Das ist definitiv nicht der Teil der weh tut ;-).

0

Du könntest das script profilen, um zu sehen, wo die Zeit verbrannt wird.

Was nen Versuch Wert wäre, Du arbeitest mit Listen und hängst an diese an. Wenn Dein Datentyp homogen ist, dann könntest Du ein Array verwenden, das ist ein Eck schneller.

Der Atan ist natürlich ein schwergewicht, überlege Dir, ob Du ihn brauchst. Kannst du den Wertebereich einschränken? Denn dann könnte man diesen als Tabelle vorberechnen.

Ich reiche noch was nach:

>>> timeit.timeit("[atan(x) for x in range(120000)]",number=100,setup="from __main__ import atan")
5.1103681640233845

Ja, der atan braucht etwas, aber so wirklich arg ist der auch nicht.


Croover 
Fragesteller
 19.12.2021, 16:42

Wenn ich die Funktion ohne

g = grav_v(X, Y)

laufen lasse, geht es schneller als in einer Sekunde. Daran liegt es also. Viel machen kann ich da aber leider nicht. Es liegt denke ich einfach daran, dass ich für 40.000 Punkte jeweils 300 Wiederholungen habe, wobei jede einzelne Wiederholung weniger als 6e-6 Sekunden braucht, was dann gute zwei Minuten sind.

0
KarlRanseierIII  19.12.2021, 17:42
@Croover

Dann an grav_v rumschrauben. Die erste Frage: welche Exception kann auftreten, die Du fangen willst?

1
Croover 
Fragesteller
 19.12.2021, 19:39
@KarlRanseierIII

Die Entfernung der Punkte ist Null und man teilt durch Null, was durchaus auftreten kann. Es handelt sich um eine Gravitationssimulation, wobei man die Anfangsgeschwindigkeit variiert.

0
KarlRanseierIII  19.12.2021, 20:31
@Croover

Dann prüfe erst auf 0, wenn ja, dann führe ein next aus. wenn ab dem ersten mal 0 es dauerhaft bei 0 bleiben muß, dann kannst Du sogar ein break machen. (Falls dort mit den Schritten eien Art 'Annäherung' stattfindet).

Eine Exception bedeutet eine unnötige Objektinstanziierung. Sie sollte nicht zu lax genutzt werden.

1

Auf Anhieb: Schmeiß die beiden print-Aufrufe raus.


Croover 
Fragesteller
 19.12.2021, 13:01

Die sind nur für mich, damit ich eine ungefähre Ahnung habe, wie weit das Programm ist. Wenn man das nämlich zwei Stunden laufen lässt, ist es immer ganz nützlich zu wissen, ob man noch eine Minute oder zwei weitere Stunden benötigt.

0
Zahhak  19.12.2021, 13:03
@Croover

Trotzdem verzögern die Dinger den Ablauf z.T. ziemlich extrem.

Sinnvoller wäre es da, z.B. nur alle 5 Minuten eine Ausgabe zu machen.

1
Zahhak  19.12.2021, 13:11
@Croover

Beginne mit

import time

, dann setz das vor den Beginn deiner Schleifen:

statusTime = time.time()

und ersetze schließlich

print(p / (200 * smoothness))

durch

if time.time() - statusTime >= 300:
    print(p / (200 * smoothness))
    statusTime = time.time()

Das wäre so ziemlich die einfachste Art das umzusetzen.

1