3

Ich benutze Python Multiprocessing-Lib, um etwas Code zu beschleunigen (Kleinste Quadrate passend zu scipy).Python Multiprocessing-Modul: seltsames Verhalten und Prozessorlast bei Verwendung von Pool

Es funktioniert gut auf 3 verschiedenen Maschinen, aber es zeigt ein seltsames Verhalten auf einer 4. Maschine.

Der Code:

import numpy as np 
from scipy.optimize import least_squares 
import time 
import parmap 
from multiprocessing import Pool 

p0 = [1., 1., 0.5] 

def f(p, xx): 
    return p[0]*np.exp(-xx ** 2/p[1] ** 2) + p[2] 

def errorfunc(p, xx, yy): 
    return f(p, xx) - yy 

def do_fit(yy, xx): 
    return least_squares(errorfunc, p0[:], args=(xx, yy)) 

if __name__ == '__main__': 
    # create data 
    x = np.linspace(-10, 10, 1000) 
    y = [] 
    np.random.seed(42) 
    for i in range(1000): 
     y.append(f([np.random.rand(1) * 10, np.random.rand(1), 0.], x) + np.random.rand(len(x))) 

    # fit without multiprocessing 
    t1 = time.time() 
    for y_data in y: 
     p1 = least_squares(errorfunc, p0[:], args=(x, y_data)) 
    t2 = time.time() 
    print t2 - t1 

    # fit with multiprocessing lib 
    times = [] 
    for p in range(1,13): 
     my_pool = Pool(p) 
     t3 = time.time() 
     results = parmap.map(do_fit, y, x, pool=my_pool) 
     t4 = time.time() 
     times.append(t4-t3) 
     my_pool.close() 
    print times 

Für die 3 Maschinen, bei denen es funktioniert, beschleunigt es etwa in der erwarteten Art und Weise nach oben. Z.B. es gibt auf meinem i7 Laptop:

[4.92650294303894, 2.5883090496063232, 1.7945551872253418, 1.629533052444458, 
1.4896039962768555, 1.3550388813018799, 1.1796400547027588, 1.1852478981018066, 
1.1404039859771729, 1.2239141464233398, 1.1676840782165527, 1.1416618824005127] 

Ich bin mit Ubuntu 14.10, Python 2.7.6, numpy 1.11.0 und 0.17.0 scipy. Ich testete es auf einem anderen Ubuntu-Rechner, einem Dell PowerEdge R210 mit ähnlichen Ergebnissen und auf einem MacBook Pro Retina (hier mit Python 2.7.11 und den gleichen numpy und scipy Versionen).

Der Computer, der Probleme verursacht, ist ein PowerEdge R710 (zwei Hexcores) mit Ubuntu 15.10, Python 2.7.11 und derselben numpy und scipy Version wie oben. Allerdings beobachte ich keine Beschleunigung. Die Zeiten liegen bei 6 Sekunden, egal welche Poolgröße ich verwende. In der Tat ist es für eine Poolgröße von 2 etwas besser und wird für mehr Prozesse schlechter.

htop zeigt, dass irgendwie mehr Prozesse hervorgebracht werden, als ich erwarten würde.

z. auf meinem Laptop htop zeigt einen Eintrag pro Prozess (der die Poolgröße entspricht) und schließlich zeigt jeder Prozess 100% CPU-Auslastung.

Auf dem PowerEdge R710 sehe ich etwa 8 Python-Prozesse für eine Poolgröße von 1 und etwa 20 Prozesse für eine Poolgröße von 2 usw., von denen jede 100% CPU-Last anzeigt.

Ich überprüft BIOS-Einstellungen des R710 und ich konnte nichts ungewöhnliches finden. Was soll ich suchen?

EDIT: Als ich auf den Kommentar antwortete, benutzte ich ein anderes einfaches Skript. Überraschenderweise scheint dies ein zu ‚Arbeit‘ für alle Maschinen:

from multiprocessing import Pool 
import time 
import math 
import numpy as np 

def f_np(x): 
    return x**np.sin(x)+np.fabs(np.cos(x))**np.arctan(x) 

def f(x): 
    return x**math.sin(x)+math.fabs(math.cos(x))**math.atan(x) 

if __name__ == '__main__': 
    print "#pool", ", numpy", ", pure python" 
    for p in range(1,9): 
     pool = Pool(processes=p) 
     np.random.seed(42) 
     a = np.random.rand(1000,1000) 
     t1 = time.time() 
     for i in range(5): 
      pool.map(f_np, a) 
     t2 = time.time() 
     for i in range(5): 
      pool.map(f, range(1000000)) 
     print p, t2-t1, time.time()-t2 
     pool.close() 

gibt:

#pool , numpy , pure python 
1 1.34186911583 5.87641906738 
2 0.697530984879 3.16030216217 
3 0.470160961151 2.20742988586 
4 0.35701417923 1.73128080368 
5 0.308979988098 1.47339701653 
6 0.286448001862 1.37223601341 
7 0.274246931076 1.27663207054 
8 0.245123147964 1.24748778343 

auf der Maschine, die die Probleme verursacht. Es gibt keine weiteren Threads (oder Prozesse?), Als ich erwartet hätte.

Es sieht aus wie numpy ist nicht das Problem, aber sobald ich scipy.optimize.least_squares verwenden, tritt das Problem auf.

Verwendung auf htop auf die Prozesse zeigt viel sched_yield() Anrufe, die ich, wenn ich scipy.optimize.least_squares und die ich auch auf meinem Laptop nicht sehen, auch nicht verwenden nicht sehen, wenn least_squares verwenden.

+1

Da Sie 'htop' verwenden, wählen Sie jeden der 8 Python-Prozesse auf dem fehlerhaften Rechner und drücken Sie' s' für 'strace'. Sehen Sie, was jeder Prozess mit dieser 100% CPU-Zeit macht. Versuchen Sie auch ein einfacheres Testprogramm, das Numpy überhaupt nicht verwendet. –

+0

Ich habe meinen ursprünglichen Beitrag bearbeitet. Ich habe das komplexere Beispiel zuerst verwendet, weil es meinem letzten Problem näher kommt. –

+0

Versuchen wir herauszufinden, wo diese Prozesse entstehen, sollen wir? Sie können Ihr Programm unter einem Debugger, z. 'gdb --arg python yescript.py' ... dann' break fork' um zu stoppen, wenn ein neuer Prozess erstellt wird, dann schaue, was die Forking macht. Es könnte die zugrundeliegenden C- oder Fortran-Routinen in Scipy sein. Siehe https://sourceware.org/gdb/onlinedocs/gdb/Forks.html –

Antwort

2

Laut here gibt es ein Problem, wenn OpenBLAS zusammen mit joblib verwendet wird.

Ähnliche Probleme treten auf, wenn MKL verwendet wird (siehe here). Die Lösung ist hier gegeben, auch für mich gearbeitet:

Hinzufügen
import os 
os.environ['MKL_NUM_THREADS'] = '1' 

am Anfang meiner Python-Skript löst das Problem.