Perché il multiprocessing utilizza solo un singolo core dopo aver importato numpy?


127

Non sono sicuro che ciò valga di più come un problema del sistema operativo, ma ho pensato di chiedere qui nel caso in cui qualcuno abbia qualche intuizione dalla fine delle cose di Python.

Ho provato a parallelizzare un forloop pesante per CPU usando joblib, ma trovo che invece di ogni processo di lavoro assegnato a un core diverso, finisco con tutti loro assegnati allo stesso core e nessun guadagno in termini di prestazioni.

Ecco un esempio molto banale ...

from joblib import Parallel,delayed
import numpy as np

def testfunc(data):
    # some very boneheaded CPU work
    for nn in xrange(1000):
        for ii in data[0,:]:
            for jj in data[1,:]:
                ii*jj

def run(niter=10):
    data = (np.random.randn(2,100) for ii in xrange(niter))
    pool = Parallel(n_jobs=-1,verbose=1,pre_dispatch='all')
    results = pool(delayed(testfunc)(dd) for dd in data)

if __name__ == '__main__':
    run()

... ed ecco cosa vedo htopmentre questo script è in esecuzione:

htop

Sto eseguendo Ubuntu 12.10 (3.5.0-26) su un laptop con 4 core. Chiaramente joblib.Parallelsta generando processi separati per i diversi lavoratori, ma c'è un modo in cui posso fare eseguire questi processi su core diversi?


stackoverflow.com/questions/15168014/… - nessuna risposta lì temo, ma sembra lo stesso problema.
NPE,



Questo è ancora un problema? Sto cercando di ricreare questo con Python 3.7 e importare numpy con multiprocessing.Pool (), e sta usando tutti i thread (come dovrebbe). Voglio solo assicurarmi che sia stato risolto.
Jared Nielsen,

Risposte:


148

Dopo qualche altro google ho trovato la risposta qui .

Risulta che alcuni moduli Python ( numpy, scipy, tables, pandas, skimage...) confusione con affinità nucleo importazione. Per quanto ne so, questo problema sembra essere stato causato in modo specifico dal loro collegamento con le librerie OpenBLAS multithread.

Una soluzione alternativa consiste nel ripristinare l'affinità dell'attività mediante

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

Con questa riga incollata dopo l'importazione del modulo, il mio esempio ora funziona su tutti i core:

htop_workaround

Finora la mia esperienza è stata che questo non sembra avere alcun effetto negativo sulle numpyprestazioni, sebbene questo sia probabilmente specifico per macchina e compito.

Aggiornare:

Esistono anche due modi per disabilitare il comportamento di ripristino dell'affinità della CPU di OpenBLAS stesso. In fase di esecuzione è possibile utilizzare la variabile di ambiente OPENBLAS_MAIN_FREE(o GOTOBLAS_MAIN_FREE), ad esempio

OPENBLAS_MAIN_FREE=1 python myscript.py

In alternativa, se stai compilando OpenBLAS dal sorgente puoi disabilitarlo permanentemente in fase di compilazione modificando il file Makefile.ruleper contenere la riga

NO_AFFINITY=1

Grazie, la tua soluzione ha risolto il problema. Una domanda, ho lo stesso codice ma corro in modo diverso su una macchina diversa. Entrambe le macchine sono Ubuntu 12.04 LTS, python 2.7, ma solo una presenta questo problema. Hai idea del perché?
iampat,

Entrambe le macchine hanno OpenBLAS (compilato con OpenMPI).
iampat,

2
Vecchio thread, ma nel caso in cui qualcun altro trovi questo problema, ho avuto il problema esatto ed era effettivamente correlato alle librerie OpenBLAS. Vedi qui per due possibili soluzioni alternative e alcune discussioni correlate.
Gabriel,

2
Un altro modo per impostare l'affinità con la cpu è usarepsutil .
Ioannis Filippidis,

2
@JHG È un problema con OpenBLAS piuttosto che con Python, quindi non vedo alcun motivo per cui la versione di Python possa fare la differenza
ali_m,

27

Python 3 ora espone i metodi per impostare direttamente l'affinità

>>> import os
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
>>> os.sched_setaffinity(0, {1, 3})
>>> os.sched_getaffinity(0)
{1, 3}
>>> x = {i for i in range(10)}
>>> x
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> os.sched_setaffinity(0, x)
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}

1
Errore> AttributeError: il modulo 'os' non ha attributi 'sched_getaffinity', Python 3.6
Paddy

4
@Paddy Dalla documentazione collegata: sono disponibili solo su alcune piattaforme Unix.
BlackJack,

2
Ho lo stesso problema, ma ho integrato questa stessa riga in alto os.system ("tasket -p 0xff% d"% os.getpid ()) ma non usa tutto cpu
rajeshcis il

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.