PyPy mit Anaconda?

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

Hallo,

in einem anderen Forum wurde mir der alternative PyPy Interpreter/ Compiler für GIL freies paralleles Programmieren empfohlen.

Wie kann ich PyPy im Zusammenspiel mit Anaconda distro installieren?

Gruss und Dank
Consuli
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
BlackJack

@consuli: Für das was Du willst vergiss Python einfach. Andererseits wird Python mit GIL für das was machen willst, ja bereits verwendet. Also ist die Frage was Du nun genau gegen `multiprocessing` hast, oder wo dich das GIL konkret behindert.

Du willst ja sicher nicht nur ”reines” Python verwenden, sondern die üblichen Bibliotheken die man bei wissenschaftlichen Rechnen so verwendet, also Numpy, Scipy, Matplotlib, Pandas, … — die werden aber nicht mit PyPy laufen. An Numpy wird zwar gearbeitet, aber warten möchte man da vielleicht nicht drauf wenn man *jetzt* Code schreiben will/muss.

Ich sehe auch nicht unbedingt das, wie von Dir behauptet, viele auf eine andere GIL-freie Python-Implementierung umsteigen. Könnte man zum Beispiel mit Jython ja jetzt schon haben. Aber ich sehe auch noch nicht das Python 2.7 in absehbarer Zukunft nicht mehr verwendet wird, oder das ich davon so schnell weg kommen werde. Wenn das mit Python 3.x so weiter geht das Python 4 den scherzhaften Codenamen „Java“ bekommt, muss ich mich vielleicht sowieso nach einer anderen Sprache umschauen. :twisted:
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

PyPy hat auch einen GIL. Es gibt im Rahmen des PyPy Projektes einen Ansatz den durch Software Transactional Memory (STM) zu ersetzen aber dass ist noch in der Entwicklung. Darüberhinaus ist die einzige Sprache in der man meines Wissens von STM ernsthaft Gebrauch machen kann Haskell. Es ist also nicht unbedingt die einfachste Lösung.

Außerdem können bei STM Transaktionen schief gehen und wenn dass zu häufig passiert muss man wissen was diese Transaktionen überhaupt sind, wieso sie schief laufen können, woran man merkt dass das zu häufig passiert und wie man das Problem löst. So ganz ohne Probleme wäre STM also auch nicht.
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

Ich arbeite zur Zeit sehr viel mit grösseren Simulationen (um 1 Mio Datenzeilen aber wenig Spalten), die ich gerne parallelisieren würde. Wenn ich mit Library multiprocessing 1 Mio Prozesse aufmache, kommt das nicht überhaupt nicht gut. Wie kann ich für Numerical Python denn meine Prozessorkerne auslasten?

Consuli
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du sollst ja auch nicht 1000000 Prozesse aufmachen - sondern so viele, wie du Cores/Hyperthreads hast.

Und ob das fuer dein Problem funktioniert kannst nur du wissen. Wenn du du deine 1M Zeilen in 8 Batches zu 125K Zeilen aufteilst & die jeweils an einen Prozess gibst, dann rechnet der das schon in der 8-fachen Geschwindigkeit aus (8 Cores vorausgesetzt).

Nur wenn die einzelnen Berechnungen voneinander abhaengen - dann ist halt essig.
BlackJack

@consuli: Wenn Du eine Million Zeilen mit *wenig* Spalten hast, dann willst Du ganz sicher nicht eine Million Operationen parallel ausführen. Auch nicht ohne GIL. Das macht keinen Sinn. Selbst wenn Du das ganz ”normal” mit `multiprocessing` bearbeitest, also jede Zeile einzeln an einen Prozess fütterst, wird der `Pool` das ja auf eine von Dir sinnvoll gewählte Anzahl von parallelen Prozessen verteilen. Und statt da die Zeilen einzeln zu verteilen, könntest Du auch die Million durch die Anzahl der Prozesse im Pool teilen und jedem Prozess dann den entsprechenden Happen an Daten zum fressen geben.
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

Ah, ich hatte vermutet ich kann dem multiprocessing die 1 Mio Iterationen in einem Rutsch übergeben und es überlegt sich selbst, wie viele der 1 Mio möglichen Prozesse es dann "im eigenen Ermessen" tatsachlich aufmacht.

Aber ich muss die Daten/ Iterationen zuerst von Hand in 8 mundgerechte multiprocessing Häppchen splitten und nachher die Teile wieder zusammenhängen. Wenn ich 25 rechenintensive Verarbeitungen habe, das ganze 25 Mal oder ich Schleife 8 Teile durch das ganze Programm. Und dann kann ich noch ausklamüsern, ob meine Berechnungen in einem Gesamten Brocken schneller zu Parallelisieren sind oder in Bröckchen. Und für einen anderen Rechner mit 12 Cores schreibe ich das Programm einfach um. Na, das ist ja komfortabel ... :(

Ist das nicht in anderen Programmiersprachen so, wenn ich Threads in einer Schleife laufen lasse, dass der Compiler sie mir AUTOMATISCH auf die Cores legt? Je nach Rechner AUTOMATISCH auf 2, 4, 6, 8, .... Cores?

Consuli
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Nein ist es nicht, zumindest nicht so wie du dir es vorstellst. Es gibt Bibliotheken die sowas einfacher machen aber vollkommen automatisch und schnell geht nicht.
BlackJack

@consuli: Das kann gar nicht alles automatisch gehen, weil das sinnvolle Vorgehen ja von den Daten und den Operationen abhängt. Zum Beispiel willst Du bei einem Numpy-Array oder Pandas-Dataframe mit einer Million Zeilen ja gar nicht eine Million einzelne Operationen haben, denn dann verspielst Du eine der wesentlichen Stärken und Geschwindigkeitsvorteile von diesen Datentypen, nämlich die internen Schleifen, die in C, C++, oder Fortran geschrieben sind, und unter Umständen sogar spezielle SIMD-Maschinenbefehle verwenden. Und einiges davon gibt auch das GIL frei, so dass selbst Threads in CPython etwas bringen können.

`multiprocessing` macht für einen Pool (maximal) so viele Prozesse auf, wie Prozessorkerne vorhanden sind. Ausser man macht selber eine Vorgabe.

Auf wie viele Häppchen man ein Problem aufteilt, hängt davon ab wie regelmässig die Laufzeit pro Häppchen verteilt sind. Wenn die alle ungefähr gleich lang brauchen, dann kann man die Gesamtmenge einfach durch die Prozessanzahl teilen. Ansonsten kann es Sinn machen durch ein vielfaches der Prozessorkerne zu teilen. So dass die Prozess gleichmässiger ausgelastet werden können. Das sind auch Entscheidungen die der Rechner nicht automatisch treffen kann. Im Grunde oft nicht einmal der Programmierer ohne das tatsächlich mal mit plausiblen Eingabedaten getestet zu haben.

Warum musst Du für einen Rechner mit 12 Kernen etwas umschreiben? Man kann die Aufteilung dynamisch abhängig von der Anzahl der Kerne machen. Eventuell muss man bei deutlich mehr Kernen etwas experimentieren wie klein Häppchen werden können, bevor das Parallelisieren mehr Aufwand als Nutzen bringt. Auch das kann der Rechner nicht automagisch im voraus entscheiden.

„Threads in einer Schleife laufen lassen“ macht als Aussage für mich keinen Sinn. Threads laufen eigenständig. Und das Betriebssystem weist die in der Regel einem Prozessorkern zu. Der kann im Laufe der Zeit auch wechseln. Das hat nichts mit der Programmiersprache zu tun, sofern Thread hier POSIX Thread meint. Die meisten Programmiersprachen benutzen diese API für Threads. Da ist kein Unterschied zwischen C, Java, …, oder auch CPython. Letzteres startet auch ganz normale Threads, nur hat der Interpreter ein globales Lock, welches verhindert das *Bytecode von der Python-VM* in mehr als einem Thread gleichzeitig ausgeführt wird. Erweiterungsmodule die in C oder einer anderen Sprache geschrieben sind, können dieses Lock freigeben solange sie nichts am Interpreter-Zustand ändern. Also zum Beispiel auch Numpy-Array-Operationen.
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

Wenn ich NON-Numpy Funktionen und NON-Pandas Funktionen auf TimeSeries oder Dataframe Objekte anwende, dann werden sie zwar vektorisiert (schnellere Schleife), aber nicht parallelisiert, oder doch? In meinem Fall sind die NON-Numpy Funktionen und NON-Pandas Funktionen in Python selbstgeschriebene Funktionen. Und die sind natürlich der Flaschenhals, nicht die allfällig äussere Schleife. Ein Numpy/ Pandas Equivalent gibt es eben nicht. Ich versuche ein neues (von mir zu entwickelndes) GLM Verfahren zu prototypen.
BlackJack hat geschrieben:@consuli: Das kann gar nicht alles automatisch gehen, weil das sinnvolle Vorgehen ja von den Daten und den Operationen abhängt.
Yes, it can. Aber es basiert nicht auf Threads, wie ich vermutete.

Aber zurück zu dem was Python kann. Ich verstehe insbesondere nicht, wie ich die Ergebnisse aus den multiprocessing Subprozessen wieder zusammenfügen soll.

In R (woher ich ja herkomme) ist das sehr elegant gelöst.

Code: Alles auswählen

library(doParallel) 

registerDoParallel(cores=8) 

result = foreach(i=1:1000000) %dopar% {  
  a=rnorm()
}
Da muss ich mir nix überlegen wie splitten und wie wieder zusammensammeln.
Zuletzt geändert von consuli am Samstag 3. Dezember 2016, 18:49, insgesamt 1-mal geändert.
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@consuli: multiprocessing kennt map, was genau das macht, wie Du Dir das vorstellst. Bei numpy-Arrays ist das aber ziemlich langsam, weil wie BlackJack schon geschrieben hat, man eigentlich Vektoroperationen benutzen möchte, statt jeden einzelnen Wert an einen anderen Prozess zu schicken.
BlackJack

@consuli: No it can't, denn gleich im ersten Absatz steht ja: „Though the quality of automatic parallelization has improved in the past several decades, fully automatic parallelization of sequential programs by compilers remains a grand challenge due to its need for complex program analysis and the unknown factors (such as input data range) during compilation.“

Ausserdem ist das alles auf einer Ebene die nichts mit Python zu tun hat.

Das was Du in R machst, geht wahrscheinlich in Python genau so ohne zu überlegen (ich kenne R nicht so gut als das ich sagen könnte in wie weit das folgende abweicht):

Code: Alles auswählen

#!/usr/bin/env python
from __future__ import absolute_import, division, print_function
from multiprocessing import Pool


def do_work(i):
    return i * 2


def main():
    pool = Pool(8)
    result = pool.map(do_work, xrange(1000000))
    print(result[:20])


if __name__ == '__main__':
    main()
Aber was genau macht R denn da? Wie trifft es die Entscheidungen? Weisst Du das überhaupt? Und ist das dann auch (zufällig) das was sinnvoll wäre?
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

Auf jeden Fall lastet der genannte R Code die Prozessoren aus und liefert das, was er soll. Ob man das noch weiter optimieren könnte, weiss ich nicht.

Ja eben nicht

Code: Alles auswählen

print(result[:20])
Ich will ja den kompletten TimeSeries/ Data.Frame zurück geliefert haben. Kann mir main() denn einen Dataframe zurück liefern?

Ausserdem habe ich im Python Manual gelesen das concurrent.futures nicht nur asynchron sondern auch parallel kann. Käme das auch in Frage?

Gruss und Dank
Consuli
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Ob `concurrent.futures` oder `multiprocessing` ist im Grunde nur eine Frage der API. Ich glaube du hast eine falsche Definition von "asynchron" im Kopf.

`print(result[:20])` gibt nur die ersten 20 Elemente aus, das heisst aber nicht, dass es nur 20 gibt. Result beinhaltet natürlich alle Ergebnisse.
the more they change the more they stay the same
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

consuli hat geschrieben:Auf jeden Fall lastet der genannte R Code die Prozessoren aus und liefert das, was er soll.
Prozessoren auslasten ist natürlich prinzipiell gut aber die sollen natürlich auch sinnvoll ausgelastet sein.

In der Praxis hast du häufig das Problem dass die Aufteilung und Kommunikation der Daten soviel Zeit kostet dass es sehr häufig schneller ist auf einem Core zu bleiben, gerade bei numerischen Sachen die CPU-bound sind.

Bibliotheken wie parallel (grundsätzlich ziemlich interessant weil es ohne concurrency auskommt) für Haskell und Rayon für Rust lösen dies indem innerhalb der Bibliothek zur Laufzeit entschieden wird was tatsächlich parallel ausgeführt wird und was nicht. Als Benutzer gibst du dann nur noch Hinweise dafür was parallel ausgeführt werden könnte.
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

Bibliotheken wie parallel (grundsätzlich ziemlich interessant weil es ohne concurrency auskommt) für Haskell und Rayon für Rust lösen dies indem innerhalb der Bibliothek zur Laufzeit entschieden wird was tatsächlich parallel ausgeführt wird und was nicht. Als Benutzer gibst du dann nur noch Hinweise dafür was parallel ausgeführt werden könnte.
Ja, eben. Laut den Scientific Programming in C++ Büchern gibt es in C++ schon seit Jahren Bibliotheken zur parallelen Ausführung (MPI, Open MPI, BLAS, ...). Deshalb bin ich als Umsteiger von R auf Python, das ja in Gegensatz zu R den Anspruch erhebt eine vollwertige Programmiersprache zu sein, von dessen Parallelisierungsfähigkeiten erstmal ziemlich enttäuscht.

Was versteckt sich eigentlich hinter dem Begriff "concurrency"? Habe ich auch schon im Python Manual gelesen und bereits dort nicht verstanden.
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
BlackJack

@consuli: Es gibt MPI-Anbindungen für Python. Das ist Interprozess-Kommunikation Und was BLAS jetzt mit paralleler Ausführung zu tun hat ist mir nicht wirklich klar. Das sind Routinen die auf Arrays operieren. NumPy nutzt das. Ich habe das Gefühl Du wirfst hier einiges durcheinander.

Eine ”vollwertige” Programmiersprache zu sein bedeutet nicht das die jetzt gerade für Deinen speziellen Anwendungsfall die geeingnetste Sprache ist. C++ ist auch eine ”vollwertige” Programmiersprache. Python und C haben sicher eine Schnittmenge für die sie geeignet sind, aber auch jeweils eigene Stärken wo die andere Sprache nicht so gut geeignet ist. Ich würde beispielsweise keine Webanwendung in C++ schreiben wollen.

Python ist auch für Scientific Computing geeignet, und wird dafür ja auch verwendet. Dabei ist nicht das reine ”number crunching” die Stärke von Python. Die Bibliotheken die dafür verwendet werden, also Numpy & Co, sind in C, C++, und Fortran geschrieben. Wenn sich ein Problem nicht in Operationen mit den Funktionen und Datentypen aus diesen Bibliotheken ausdrücken lässt, also *viele* Operationen in Python-Bytecode auszuführen sind, dann ist Python vielleicht nicht die richtige Sprache. Oder zumindest nicht alleine, denn man kann ja genau wie die genannten Bibliotheken das machen, seinen Code in Python *und* einer anderen Sprache schreiben.

Nur mal so aus Neugier: Hast Du schon ein Programm das fehlerfrei läuft oder versenkst Du hier erst einmal Zeit in die theoretische Parallelisierung von etwas das noch gar nicht existiert? Und warum verwendest Du nicht C++?
consuli
User
Beiträge: 52
Registriert: Sonntag 26. Juli 2015, 22:10

BlackJack hat geschrieben: Nur mal so aus Neugier: Hast Du schon ein Programm das fehlerfrei läuft ?
Ich habe ein R Programm dass den Kernteil des Problems in einem eingeschränkten Parameterraum löst. Dieses Programm möchte ich aus Vorbild und Performance Gründen nach Python portieren und zur Vollständigkeit ausbauen. Dabei soll die Python GLM Programmierung in genmod als Vorbild dienen.
BlackJack hat geschrieben: Oder versenkst Du hier erst einmal Zeit in die theoretische Parallelisierung von etwas das noch gar nicht existiert?
Ja, ich kläre die technischen Gegebenheiten
- Datentypen (Vektoren, Matrizen, Dataframes)
- Funktionalitäten (Matrizenmultiplikatione, numerische Optimierungsfunktionen, ...)
- Performance (Parallele Programmierung, (Byte)Compilierung, ...)
vorher ab. Der worst case wäre, dass auf der Hälfte des Projekts die Programmiersprache wechseln müsste.
BlackJack hat geschrieben: Oder zumindest nicht alleine, denn man kann ja genau wie die genannten Bibliotheken das machen, seinen Code in Python *und* einer anderen Sprache schreiben. Warum verwendest Du (zusätzlich) nicht C++?
Ja, dass ist ein sehr guter Hinweis. Leider kann ich kein C++ (bis auf ganz paar Basics von einem Unikurs vor x Jahren). Zwischenzeitlich habe ich jedoch rausgefunden das Cython (im Verleich zu pur C++) relativ einfache und doch performante, insbesondere GIL und Prozess-Wasserkopf freie, Parallelprogrammierung ermöglicht.
Who controls the British crown? Who keeps the metric system down? We do! We do!
Who leaves Atlantis off the maps? Who keeps the Marsians under wraps? We do! We do!
BlackJack

@consuli: Wenn Du etwas aus Performancegründen von R nach Python portieren möchtest, dann möchtest Du das vielleicht gar nicht nach Python portieren. Performance ist nicht unbedingt das erste was mir bei Python einfällt. Also was die Ausführung von Rechnungen angeht, nicht was die Entwicklung von Programmen angeht.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

consuli hat geschrieben: Ja, dass ist ein sehr guter Hinweis. Leider kann ich kein C++ (bis auf ganz paar Basics von einem Unikurs vor x Jahren). Zwischenzeitlich habe ich jedoch rausgefunden das Cython (im Verleich zu pur C++) relativ einfache und doch performante, insbesondere GIL und Prozess-Wasserkopf freie, Parallelprogrammierung ermöglicht.
Wo steht das, bzw. wie sieht das genau aus? In dieser Absolutheit halte ich die Aussage fuer etwas gewagt - so toll Cython ist.
Antworten