Die meisten Funktionen des Numpy aktivieren standardmäßig Multithreading.
Ich arbeite beispielsweise auf einer Intel-CPU-Workstation mit 8 Kernen, wenn ich ein Skript ausführe
import numpy as np
x=np.random.random(1000000)
for i in range(100000):
np.sqrt(x)
Das Linux top
zeigt 800% CPU-Auslastung während des Betriebs an,
was bedeutet, dass numpy automatisch erkennt, dass meine Workstation 8 Kerne hat, und np.sqrt
automatisch alle 8 Kerne verwendet, um die Berechnung zu beschleunigen.
Ich habe jedoch einen seltsamen Fehler gefunden. Wenn ich ein Skript ausführe
import numpy as np
import pandas as pd
df=pd.DataFrame(np.random.random((10,10)))
df+df
x=np.random.random(1000000)
for i in range(100000):
np.sqrt(x)
Die CPU-Auslastung beträgt 100% !!. Dies bedeutet, dass die automatische Multithreading-Funktion von numpy ohne Vorwarnung wegfällt, wenn Sie vor dem Ausführen einer Numpy-Funktion zwei Pandas DataFrame plus verwenden! Dies ist absolut nicht sinnvoll. Warum wirkt sich die Berechnung von Pandas dataFrame auf die Numpy-Threading-Einstellung aus? Ist es ein Fehler? Wie kann man das umgehen?
PS:
Ich grabe weiter mit Linux- perf
Tool.
Das erste Skript wird angezeigt
Beim Ausführen zeigt das zweite Skript
Beide Skripte beinhalten also libmkl_vml_avx2.so
, während das erste Skript zusätzliche beinhaltet libiomp5.so
, die mit openMP in Zusammenhang zu stehen scheinen.
Und da vml Intel Vector Math Library bedeutet, werden laut vml doc zumindest die folgenden Funktionen automatisch alle multithreaded
import numpy as np import pandas as pd import os os.environ["MKL_NUM_THREADS"] = '4' print(os.environ["MKL_NUM_THREADS"]) df=pd.DataFrame(np.random.random((10,10))) df+df print(os.environ["MKL_NUM_THREADS"]) a = np.random.random((20000000, 3)) b = np.random.random((3, 30)) for _ in range(10): c = np.dot(a, b)
Antworten:
Pandas Anwendungen
numexpr
unter der Haube einige Operationen zu berechnen, undnumexpr
stellt die maximale Anzahl von Threads für VML auf 1, wenn es eingeführt wird :und es wird von Pandas importiert, wenn
df+df
es in expression.py ausgewertet wird :Jedoch auch Anaconda Verteilung verwendet VML-Funktionalität für solche Funktionen wie
sqrt
,sin
,cos
und so weiter - und wennnumexpr
die maximale Anzahl von VML-Fäden 1, die numpy-Funktionen nicht länger Verwendung Parallelisierung eingestellt.Das Problem kann leicht in gdb gesehen werden (mit Ihrem langsamen Skript):
dh wir können sehen,
numexpr
setzt die Anzahl der Threads auf 1. Was später verwendet wird, wenn die vml-sqrt-Funktion aufgerufen wird:So wir numpy Anwendungen VML-Implementierung sehen
vdSqrt
welcher verwendet ,mkl_vml_serv_threader_d_1i_1o
um zu entscheiden , ob die Berechnung parallel durchgeführt werden sollte , und es sieht die Anzahl der Threads:Das Register
%rax
hat die maximale Anzahl von Threads und ist 1.Jetzt können wir nutzen ,
numexpr
um die Anzahl der VML-Threads zu erhöhen , das heißt:Jetzt werden mehrere Kerne verwendet!
quelle
numexpr
Blick hinter die Kulissen.Wenn man sich numpy ansieht, sieht es so aus, als ob unter der Haube Probleme mit Multithreading aufgetreten sind. Je nachdem, welche Version Sie verwenden, kann es zu Abstürzen kommen, wenn Sie auf ne.set_vml_num_threads () stoßen.
http://numpy-discussion.10968.n7.nabble.com/ANN-NumExpr-2-7-0-Release-td47414.html
Ich muss mir überlegen, wie dies in den Python-Interpreter eingeklebt wird, wenn man Ihr Codebeispiel betrachtet, bei dem es irgendwie möglich zu sein scheint, dass mehrere scheinbar synchrone / geordnete Aufrufe von np.sqrt () parallel ablaufen. Ich denke, wenn der Python-Interpreter immer nur eine Referenz auf ein Objekt zurückgibt, wenn es den Stapel öffnet, und in Ihrem Beispiel nur diese Referenzen aufwirft und sie nicht in irgendeiner Weise zuweist oder manipuliert, wäre das in Ordnung. Wenn nachfolgende Schleifeniterationen jedoch von vorherigen abhängen, scheint es weniger klar zu sein, wie diese sicher parallelisiert werden können. Wohl stilles Versagen / falsche Ergebnisse sind ein Ergebnis, das schlimmer ist als Abstürze.
quelle
Ich denke, dass Ihre ursprüngliche Prämisse möglicherweise falsch ist -
Sie haben angegeben: Das bedeutet, dass numpy automatisch erkennt, dass meine Workstation 8 Kerne hat, und np.sqrt automatisch alle 8 Kerne verwendet, um die Berechnung zu beschleunigen.
Eine einzelne Funktion np.sqrt () kann nicht erraten, wie sie als nächstes aufgerufen oder zurückgegeben wird, bevor sie teilweise abgeschlossen ist. Es gibt Parallelitätsmechanismen in Python, aber keine sind automatisch.
Nun, obwohl der Python-Interpreter in der Lage sein könnte, die for-Schleife für Parallelität zu optimieren, was Sie vielleicht sehen, aber ich vermute stark, wenn Sie sich die Wanduhrzeit ansehen, für die diese Schleife ausgeführt wird, wird es nein sein unterschiedlich, unabhängig davon, ob Sie (anscheinend) 8 Kerne oder 1 Kern verwenden.
UPDATE: Nachdem Sie ein bisschen mehr von den Kommentaren gelesen haben, scheint es, als ob das Multi-Core-Verhalten, das Sie sehen, mit der Anakonda-Verteilung des Python-Interpreters zusammenhängt. Ich habe einen Blick darauf geworfen, konnte aber keinen Quellcode dafür finden, aber es scheint, dass die Python-Lizenz Entitäten (wie anaconda.com) erlaubt, Derivate des Interpreters zu kompilieren und zu verteilen, ohne dass deren Änderungen veröffentlicht werden müssen.
Ich denke, Sie können sich an die Anaconda-Leute wenden - das Verhalten, das Sie sehen, wird schwer herauszufinden sein, ohne zu wissen, was / ob sich etwas am Dolmetscher geändert hat.
Überprüfen Sie auch schnell die Wanduhrzeit mit / ohne Optimierung, um festzustellen, ob sie tatsächlich 8x schneller ist - selbst wenn wirklich alle 8 Kerne anstelle von 1 funktionieren, ist es gut zu wissen, ob die Ergebnisse tatsächlich 8x sind schneller oder wenn Spinlocks verwendet werden, die noch auf einem einzelnen Mutex serialisiert werden.
quelle