it-swarm.com.de

Python beschleunigen

Das sind eigentlich zwei Fragen, aber sie sind sich so ähnlich, und um es einfach zu halten, dachte ich, ich würde sie einfach zusammenrollen:

  • Erstens : Was sind angesichts eines etablierten Python-Projekts vernünftige Möglichkeiten, es zu beschleunigen, die über die reine In-Code-Optimierung hinausgehen?

  • Zweitens : Wenn Sie ein Programm von Grund auf in Python schreiben, was sind einige gute Möglichkeiten, um die Leistung erheblich zu verbessern?

Stellen Sie sich für die erste Frage vor, Sie erhalten ein anständiges schriftliches Projekt und müssen die Leistung verbessern, aber Sie können durch Refactoring/Optimierung scheinbar keinen großen Gewinn erzielen. Was würden Sie tun, um es in diesem Fall zu beschleunigen, ohne es in etwas wie C umzuschreiben?

42
akdom

Zu "Zweitens: Wenn Sie ein Programm von Grund auf in Python schreiben, was sind einige gute Möglichkeiten, um die Leistung erheblich zu verbessern?"

Beachten Sie die Jackson-Optimierungsregeln:

  • Regel 1: Tu es nicht.
  • Regel 2 (nur für Experten): Mach es noch nicht.

Und die Knuth-Regel:

  • "Vorzeitige Optimierung ist die Wurzel allen Übels."

Die nützlicheren Regeln finden Sie in Allgemeine Regeln für die Optimierung .

  1. Optimieren Sie nicht, während Sie gehen. Mach es zuerst richtig. Dann mach es schnell. Ein falsches Programm zu optimieren ist immer noch falsch.

  2. Erinnere dich an die 80/20 Regel.

  3. Führen Sie immer "vor" und "nach" Benchmarks aus. Andernfalls werden Sie nicht wissen, ob Sie die 80% gefunden haben.

  4. Verwenden Sie die richtigen Algorithmen und Datenstrukturen. Diese Regel sollte an erster Stelle stehen. Nichts ist so wichtig wie der Algorithmus und die Datenstruktur.

Fazit

Sie können den Aufwand zur Optimierung dieses Programms nicht verhindern oder vermeiden. Das gehört zum Job. Sie müssen es genau planen und sorgfältig ausführen, genau wie das Design, den Code und die Testaktivitäten.

41
S.Lott

Anstatt nur auf C zu punting, würde ich vorschlagen:

Lass deinen Code zählen. Machen Sie mehr mit weniger Zeilenausführungen:

  • Ändern Sie den Algorithmus auf einen schnelleren. In vielen Fällen muss es keine Lust sein, schneller zu sein.
  • Verwenden Sie Python-Primitive, die zufällig in C geschrieben sind. Manche Dinge werden einen Interpreter-Versand erzwingen, andere nicht. Letzteres ist vorzuziehen
  • Hüten Sie sich vor Code, der zuerst eine Big-Data-Struktur erstellt und anschließend konsumiert. Denken Sie an den Unterschied zwischen Reichweite und x-Bereich. Im Allgemeinen lohnt es sich oft, über die Speichernutzung des Programms nachzudenken. Die Verwendung von Generatoren kann manchmal den O(n) Speicherverbrauch auf O (1) senken.
  • Python ist im Allgemeinen nicht optimierend. Heben Sie unveränderlichen Code aus Schleifen heraus auf und beseitigen Sie in engen Schleifen, wo immer möglich, übliche Unterausdrücke.
  • Wenn etwas teuer ist, dann rechnen Sie es vor oder merken Sie es sich. Beispielsweise können reguläre Ausdrücke kompiliert werden.
  • Müssen Sie Zahlen knacken? Vielleicht möchten Sie numpy auschecken.
  • Viele Python-Programme sind langsam, weil sie durch Festplatten-E/A- oder Datenbankzugriff gebunden sind. Stellen Sie sicher, dass Sie etwas zu tun haben, während Sie darauf warten, dass die Daten eintreffen, anstatt nur zu blockieren. Eine Waffe könnte so etwas wie das Twisted Framework sein.
  • Beachten Sie, dass viele wichtige Datenverarbeitungsbibliotheken C-Versionen haben, sei es XML, JSON oder so weiter. Sie sind oft erheblich schneller als der Python-Interpreter.

Wenn alle oben genannten Probleme bei profiliertem und gemessenem Code auftreten, sollten Sie über den C-Rewrite-Pfad nachdenken.

26

Die üblichen Verdächtigen - profilieren Sie es, finden Sie die teuerste Leitung, finden Sie heraus, was sie tut, beheben Sie es. Wenn Sie zuvor noch nicht viel profiliert haben, kann es vorkommen, dass sich hinter ansonsten harmlos aussehenden Ausdrücken große, fette, quadratische Schleifen oder doppelte Zeichenfolgen verbergen.

In Python sind zwei der häufigsten Ursachen für eine nicht offensichtliche Verlangsamung die Verkettung von Zeichenfolgen und Generatoren. Da Pythons Zeichenfolgen unveränderlich sind, sollten Sie Folgendes tun:

result = u""
for item in my_list:
    result += unicode (item)

kopiert die Zeichenfolge complete zweimal pro Iteration. Dies wurde ausführlich behandelt und die Lösung ist die Verwendung von "".join:

result = "".join (unicode (item) for item in my_list)

Generatoren sind ein weiterer Schuldiger. Sie sind sehr einfach zu bedienen und können einige Aufgaben enorm vereinfachen, aber ein schlecht angewandter Generator ist viel langsamer als das einfache Anhängen von Elementen an eine Liste und das Zurückgeben der Liste.

Schließlich habe keine Angst, Bits in C umzuschreiben! Python ist als dynamische Hochsprache einfach nicht in der Lage, die Geschwindigkeit von C zu erreichen. Wenn es eine Funktion gibt, die Sie in Python nicht mehr optimieren können, ziehen Sie in Betracht, sie in ein Erweiterungsmodul zu extrahieren.

Meine Lieblingsmethode ist es, sowohl die Python- als auch die C-Version eines Moduls zu verwalten. Die Python-Version soll so klar und offensichtlich wie möglich sein - alle Fehler sollten leicht zu diagnostizieren und zu beheben sein. Schreiben Sie Ihre Tests gegen dieses Modul. Schreiben Sie dann die C-Version und testen Sie sie. Ihr Verhalten sollte in jedem Fall dem der Python-Implementierung entsprechen - wenn sie sich unterscheiden, sollte es sehr einfach sein, herauszufinden, was falsch ist, und das Problem zu beheben.

23
John Millikin

Das erste, was mir einfällt: Psyco . Es läuft vorerst nur auf x86.

Dann konstante Bindung . Das heißt, alle globalen Referenzen (und global.attr , global.attr.attr …) müssen lokale Namen innerhalb von Funktionen und Methoden sein. Dies ist nicht immer erfolgreich, aber im Allgemeinen funktioniert es. Es kann von Hand gemacht werden, ist aber offensichtlich mühsam.

Sie sagten, abgesehen von der In-Code-Optimierung, damit ich nicht näher darauf eingehen werde, aber seien Sie offen für typische Fehler (for i in range(10000000) kommt in den Sinn), die die Leute machen.

17
tzot

Cython und Pyrex können verwendet werden, um C-Code mit einer Python-ähnlichen Syntax zu generieren. Psyco eignet sich auch hervorragend für entsprechende Projekte (manchmal werden Sie nicht viel Geschwindigkeitsschub bemerken, manchmal sind es 50x so schnell). Nach wie vor ist es meiner Meinung nach am besten, Ihren Code (cProfile usw.) zu profilieren und dann nur die Engpässe als c-Funktionen für Python zu codieren.

9
hacama

Ich bin überrascht, dass niemand ShedSkin erwähnt hat: http://code.google.com/p/shedskin/ . Es konvertiert Ihr Python-Programm automatisch nach C++ und bringt in einigen Benchmarks bessere Verbesserungen als Psyco in der Geschwindigkeit.

Plus anekdotische Geschichten über die Einfachheit: http://pyinsci.blogspot.com/2006/12/trying-out-latest-release-of-shedskin.html

Es gibt jedoch Einschränkungen, siehe: http://tinyurl.com/shedskin-limitations

7
torial

Ich hoffe, Sie haben gelesen: http://wiki.python.org/moin/PythonSpeed/PerformanceTips

Wiederaufnahme dessen, was bereits vorhanden ist, gibt es normalerweise drei Prinzipien:

  • schreiben Sie Code, der sich in besseren Bytecode verwandelt, wie z. B. Verwenden von Locals, Vermeiden von unnötigen Suchen/Aufrufen, Verwenden von idiomatischen Konstrukten (wenn es eine natürliche Syntax für das gibt, was Sie möchten, verwenden Sie sie - normalerweise schneller some_dict.keys () ", do" for key in some_dict ")
  • was auch immer in C geschrieben ist, ist wesentlich schneller. Missbrauchen Sie alle verfügbaren C-Funktionen/Module
  • importieren Sie im Zweifelsfall die Zeit, das Profil
5
ionelmc

Dies beschleunigt nicht unbedingt Ihren Code, ist jedoch ein wichtiges Wissen bei der Programmierung in Python, wenn Sie verhindern möchten, dass Ihr Code langsamer wird. Die "Global Interpreter Lock" (GIL) hat das Potenzial, die Geschwindigkeit Ihres Multithread-Programms drastisch zu reduzieren, wenn sein Verhalten nicht verstanden wird Verwenden Sie mehr als 1,2 Prozessoren gleichzeitig. Es gibt einen Einführungsartikel mit einigen Links, die Ihnen den Einstieg in SmoothSpan erleichtern.

4
Steve Moyer

Führen Sie Ihre App über den Python-Profiler aus. Finden Sie einen ernsthaften Engpass. Schreiben Sie diesen Engpass in C um. Wiederholen Sie diesen Vorgang.

4
Vicent Marti

Die Leute haben einige gute Ratschläge gegeben, aber Sie müssen sich darüber im Klaren sein, dass das Python-Modell, wenn eine hohe Leistung erforderlich ist, wie folgt lautet: punt to c. Bemühungen wie Psyco können in Zukunft ein wenig helfen, aber Python ist keine schnelle Sprache, und es ist auch nicht dafür ausgelegt. Nur sehr wenige Sprachen sind in der Lage, die dynamischen Aufgaben wirklich gut zu erledigen und dennoch sehr schnellen Code zu generieren. Zumindest für die absehbare Zukunft (und ein Teil des Designs arbeitet gegen eine schnelle Kompilierung) wird dies der Fall sein.

Wenn Sie sich also wirklich in dieser Situation befinden, ist es am besten, die Teile Ihres Systems zu isolieren, die in (gutem) Python nicht akzeptabel langsam sind, und die Idee zu berücksichtigen, dass Sie diese Teile in C neu schreiben. Gutes Design kann dazu beitragen, dass dies weniger schmerzhaft ist. Prototypen Sie es jedoch zuerst in Python, dann haben Sie leicht eine Überprüfung der geistigen Gesundheit auf Ihrem c, als auch.

Das funktioniert schließlich gut genug für Dinge wie Numpy. Ich kann gar nicht genug betonen, wie viel gutes Design Ihnen dabei helfen wird. Wenn Sie nur iterativ an Ihren Python-Bits herumstöbern und die langsamsten durch C ersetzen, kann dies zu einem großen Durcheinander führen. Überlegen Sie genau, wo die C-Bits benötigt werden und wie sie sinnvoll minimiert und gekapselt werden können.

4
simon

Es ist oft möglich, C-nahe Geschwindigkeiten zu erreichen (in der Nähe genug für jedes Projekt, das Python verwendet!), Indem explizite Algorithmen, die in Python lang geschrieben wurden, durch implizite Algorithmen mit einem integrierten Python-Aufruf ersetzt werden. Dies funktioniert, weil die meisten Python-Built-Ins sowieso in C geschrieben sind. Natürlich in CPython ;-) https://www.python.org/doc/essays/list2str/

3
sep332

Dies ist die Prozedur, die ich zu befolgen versuche:

  • import Psyco; psyco.full ()
  • Wenn es nicht schnell genug ist, führen Sie den Code durch einen Profiler, um zu sehen, wo die Engpässe sind. (Psyco für diesen Schritt deaktivieren!)
  • Versuchen Sie, Dinge zu tun, von denen andere bereits gesprochen haben, um den Code bei diesen Engpässen so schnell wie möglich zu erhalten.
    • Sachen wie [str (x) für x in l] oder [x.strip () für x in l] sind viel langsamer als map (str, x) oder map (str.strip, x).
  • Wenn ich danach noch mehr Geschwindigkeit benötige, ist es wirklich sehr einfach, PyRex zum Laufen zu bringen. Ich kopiere zuerst einen Teil des Python-Codes, füge ihn direkt in den Pyrex-Code ein und sehe, was passiert. Dann tüftele ich daran, bis es immer schneller wird.
3
Claudiu

Nur eine Anmerkung zur Verwendung von Psyco: In einigen Fällen kann es tatsächlich zu langsameren Laufzeiten kommen. Besonders wenn ich versuche, Psyco mit Code zu verwenden, der in C geschrieben wurde. Ich kann mich nicht an den Artikel erinnern, den ich gelesen habe, aber die Funktionen map() und reduce() wurden speziell erwähnt. Zum Glück können Sie psyco anweisen, bestimmte Funktionen und/oder Module nicht zu handhaben.

3
Walter

Die kanonische Referenz zur Verbesserung von Python-Code finden Sie hier: PerformanceTips . Ich würde empfehlen, in C nicht zu optimieren, es sei denn, Sie müssen dies wirklich tun. Für die meisten Anwendungen erhalten Sie die Leistung, die Sie benötigen, indem Sie die in diesem Link angegebenen Regeln befolgen.

2
Jason Baker

Bei Verwendung von Psyco würde ich psyco.profile() anstelle von psyco.full() empfehlen. Für ein größeres Projekt ist es klüger, welche Funktionen optimiert wurden und viel weniger Speicher benötigen.

Ich würde auch Iteratoren und Generatoren empfehlen. Wenn Ihre Anwendung große Datenmengen verwendet, werden dadurch viele Kopien von Containern eingespart.

1
Peter Shinners

Neben dem (tollen) Psyco und dem (netten) Shedskin würde ich empfehlen, Cython eine tolle Fork von Pyrex zu probieren.

Oder, wenn Sie es nicht eilig haben, empfehle ich, nur zu warten. Neuere virtuelle Python-Maschinen kommen und unbeladen-schlucken werden den Weg in den Mainstream finden.

1
Davide

Für ein etabliertes Projekt wird meiner Meinung nach der größte Leistungsgewinn darin bestehen, die interne Python-Bibliothek so weit wie möglich zu nutzen.

Einige Tipps finden Sie hier: http://blog.hackerearth.com/faster-python-code

Nach der Beantwortung dieser Frage wurden einige Möglichkeiten zur Beschleunigung des Python-Codes vorgestellt:

  • Pypy hat einen JIT-Compiler, der es für CPU-gebundenen Code viel schneller macht.
  • Pypy ist in Rpython geschrieben, einer Teilmenge von Python, die unter Ausnutzung der LLVM-Toolkette zu nativem Code kompiliert wird.
0
Janus Troelsen