2015-07-09 18 views
7

Ich habe eine Maschine mit 24 physikalische Kerne (zumindest wurde mir gesagt) unter Debian laufen: Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u1 x86_64 GNU/Linux. Es scheint korrekt zu sein:Python: Multiprozessing, 8/24 Kerne geladen

[email protected]:~/$ cat /proc/cpuinfo | grep processor 
processor : 0 
processor : 1 
<...> 
processor : 22 
processor : 23 

ich hatte einige Probleme versuchen multiprocessing.pool.Pool alle Kerne mit Python zu laden. Ich benutzte Pool(processes=None); Die Dokumente sagen, dass Python cpu_count() verwendet, wenn None bereitgestellt wird.

Ach, nur 8 Kerne waren 100% geladen, andere blieben im Leerlauf (ich habe htop zur Überwachung der CPU-Auslastung verwendet). Ich dachte, dass ich nicht Pools kochen richtig kann und versucht, 24 Prozesse „von Hand“ aufzurufen:

print 'Starting processes...' 
procs = list() 
for param_set in all_params: # 24 items 
    p = Process(target=_wrap_test, args=[param_set]) 
    p.start() 
    procs.append(p) 

print 'Now waiting for them.' 
for p in procs: 
    p.join() 

Ich hatte 24 „Gruß“ Nachrichten von den Prozessen begann ich:

Starting processes... 
Executing combination: Session len: 15, delta: 10, ratio: 0.1, eps_relabel: 0.5, min_pts_lof: 5, alpha: 0.01, reduce: 500 
< ... 22 more messages ... > 
Executing combination: Session len: 15, delta: 10, ratio: 0.1, eps_relabel: 0.5, min_pts_lof: 7, alpha: 0.01, reduce: 2000 
Now waiting for them. 

Aber nur noch 8 Kerne wurden geladen:

enter image description here

ich habe hier auf SO gelesen, dass es m ay Probleme mit numpy, OpenBLAS und Multicore-Ausführung. Dies ist, wie ich meinen Code starten:

OPENBLAS_MAIN_FREE=1 python -m tests.my_module 

Und nach allen Importen ich tun:

os.system("taskset -p 0xff %d" % os.getpid()) 

So, hier ist die Frage: Was soll ich tun, 100% -load auf allen Kernen haben? Ist das nur meine schlechte Python-Verwendung oder hat es etwas mit OS-Beschränkungen auf Multicore-Maschinen zu tun?

AKTUALISIERT: eine weitere interessante Sache ist einige Inkonsistenz innerhalb htop Ausgabe. Wenn Sie sich das Bild oben ansehen, sehen Sie, dass die Tabelle unter den CPU-Lastbalken 30-50% Last für viel mehr als 8 Kerne anzeigt, was sich definitiv von dem unterscheidet, was Lastbalken sagen. Dann scheint mit diesen Balken übereinzustimmen: 8 Kerne 100% -geladen, andere leer.

I verwendet this rather popular post auf SO, wenn ich hinzugefügt, um die os.system("taskset -p 0xff %d" % os.getpid()) Linie, nachdem alle Importe:

ERNEUT AKTUALISIERT. Ich muss zugeben, dass ich nicht zu viel dachte, wenn ich das täte, vor allem nach der Lektüre dieses:

Mit dieser Linie nach dem Modul importiert eingefügt in, meinem Beispiel läuft nun auf allen Kernen

Ich bin ein einfacher Mann. Ich sehe "funktioniert wie ein Zauber", ich kopiere und füge hinzu. Wie auch immer, während ich mit meinem Code spiele, entferne ich diese Zeile. Danach begann mein Code auf allen 24 Kernen für das "manuelle" Process Startszenario. Für das Szenario blieb das gleiche Problem bestehen, egal ob der Affinitätstrick verwendet wurde oder nicht.

Ich glaube nicht, dass es eine echte Antwort ist, denn ich weiß nicht, was das Problem mit Pool ist, aber zumindest habe ich es geschafft, alle Kerne voll geladen zu bekommen. Vielen Dank!

+0

Sind Sie sicher, dass dies 1 Prozessorplatine ist? Ich habe das Gerücht gehört, dass Python Multiprocessing nicht ausführen kann (verwenden Sie mehr als 1 CPU) – deathangel908

+0

@ deathangel908 Ich nehme an, es hat 4 CPUs mit je 6 Kernen. Aber es verwendet bereits mehr als 6 Kerne, also ist es nicht das Problem, denke ich. – oopcode

+0

@ Deathangel908 das ist falsch: Es gibt Probleme, Threading zu erhalten, um alle Maschinenressourcen zu verwenden, aber Multiprocessing, mit separaten Unix-Prozessen, ist nicht durch Python begrenzt. Meine Vermutung ist, dass es eine Kernel-Einstellung gibt, die nicht richtig eingestellt ist, wie das OP auch vermutet hat. – msw

Antwort

2

Obwohl Sie das Problem gelöst haben, werde ich versuchen, es zu erklären, um die Ideen zu klären.

Für das, was ich gelesen habe, macht numpy eine Menge "Magie", um die Leistung zu verbessern. Einer der magischen Tricks besteht darin, die CPU-Affinität des Prozesses einzustellen.

Die CPU-Affinität ist eine Optimierung des OS-Schedulers. Es erzwingt im Grunde, dass ein bestimmter Prozess immer auf demselben CPU-Kern ausgeführt wird.

Dadurch wird die Leistung verbessert, wodurch die Anzahl der CPU-Cache-Speicher ungültig wird und die Vorteile der Referenzlokalität erhöht werden. Bei hohen Rechenaufgaben sind diese Faktoren in der Tat wichtig.

Was ich an numpy nicht mag ist die Tatsache, dass es all dies implizit tut. Oft rätselhafte Entwickler.

Die Tatsache, dass Ihre Prozesse nicht auf allen Kernen ausgeführt wurden, lag an der Tatsache, dass numpy beim Importieren des Moduls die Affinität zum übergeordneten Prozess festlegt. Wenn Sie dann die neuen Prozesse generieren, wird die Affinität vererbt und führt zu allen Prozessen, die für wenige Kerne kämpfen, anstatt alle verfügbaren effizient zu nutzen.

Der Befehl os.system("taskset -p 0xff %d" % os.getpid()) weist das Betriebssystem an, die Affinität für alle Kerne, die das Problem lösen, wieder festzulegen.

Wenn Sie sehen wollen, dass es auf dem Pool funktioniert, können Sie den folgenden Trick tun.

import os 
from multiprocessing import Pool 


def set_affinity_on_worker(): 
    """When a new worker process is created, the affinity is set to all CPUs""" 
    print("I'm the process %d, setting affinity to all CPUs." % os.getpid()) 
    os.system("taskset -p 0xff %d" % os.getpid()) 


if __name__ == '__main__': 
    p = Pool(initializer=set_affinity_on_worker) 
    ... 
Verwandte Themen