2014-10-16 14 views
5

Próbuję zoptymalizować mój kod przy użyciu modułu Pythona multiprocessing.Pool, ale nie otrzymuję wyników przyśpieszenia, których logicznie oczekiwałbym.Wieloprocesorowe przetwarzanie w języku Python nie przyspiesza oczekiwanie

Główna metoda, którą wykonuję, polega na obliczaniu produktów macierzy-wektorów dla dużej liczby wektorów i stałej dużej macierzy rzadkiej. Poniżej znajduje się przykład zabawki, który wykonuje to, czego potrzebuję, ale z losowymi matrycami.

import time 
import numpy as np 
import scipy.sparse as sp 

def calculate(vector, matrix = None): 
    for i in range(50): 
     v = matrix.dot(vector) 
    return v 

if __name__ == '__main__': 
    N = 1e6 
    matrix = sp.rand(N, N, density = 1e-5, format = 'csr') 
    t = time.time() 
    res = [] 
    for i in range(10): 
     res.append(calculate(np.random.rand(N), matrix = matrix))  
    print time.time() - t 

Sposób kończy się w ciągu około 30 sekund.

Teraz, ponieważ obliczenia każdego elementu z results nie zależy od wyników jakichkolwiek innych obliczeń, naturalne jest, że obliczenia równoległe przyspieszą proces. Chodzi o to, aby utworzyć 4 procesy i jeśli każdy wykona część obliczeń, czas potrzebny na ukończenie wszystkich procesów powinien zmniejszyć się o około jeden czynnik około 4. Aby to zrobić, napisałem poniższy kod:

import time 
import numpy as np 
import scipy.sparse as sp 
from multiprocessing import Pool 
from functools import partial 

def calculate(vector, matrix = None): 
    for i in range(50): 
     v = matrix.dot(vector) 
    return v 

if __name__ == '__main__': 
    N = 1e6 
    matrix = sp.rand(N, N, density = 1e-5, format = 'csr') 

    t = time.time() 
    input = [] 
    for i in range(10): 
     input.append(np.random.rand(N)) 
    mp = partial(calculate, matrix = matrix) 
    p = Pool(4) 
    res = p.map(mp, input) 
    print time.time() - t 

Moim problemem jest to, że kod ten trwa nieco ponad 20 sekund do uruchomienia, więc nie miałem nawet zwiększyć wydajność o czynnik 2! Co gorsza, wydajność poprawia się, nawet jeśli pula zawiera procesy ! Masz pomysł, dlaczego przyspieszenie się nie dzieje?


Uwaga: Moja rzeczywista metoda trwa znacznie dłużej, a wektory wejściowe są przechowywane w pliku. Jeśli podzielę plik na części 4, a następnie uruchomię mój skrypt w oddzielnym procesie dla każdego pliku ręcznie, każdy proces zakończy się cztery razy szybciej niż w przypadku całego pliku (zgodnie z oczekiwaniami). Ja confuzed dlaczego ta prędkość-up (co jest oczywiście możliwe) nie dzieje się z multiprocessing.Pool


Edi: Właśnie dowiedziałem Multiprocessing.Pool makes Numpy matrix multiplication slower to pytanie, które może być związane. Muszę jednak sprawdzić.

+0

Pytanie: Ile fizycznych rdzeni procesora (bez hiperwątkowości) ma system, na którym to działa? –

+0

@KlausD. Fizycznie mam rdzenie "4". Właśnie dlatego ręcznie dzielę ten plik na fragmenty "4", a nie "8". – 5xum

+0

Jeśli umieścisz kilka testów porównawczych 'time.time()' w swojej metodzie 'calculate', zobaczysz, że 50-kropkowe połączenia są prawie 4 razy dłuższe niż w przypadku nierównoległym. Nie wiem dlaczego, ponieważ narzędzia takie jak "top" sprawiają, że przypadek nierównolegania wykorzystuje tylko jeden procesor, podczas gdy równoległy przypadek sprawia, że ​​4 procesory są w pełni wykorzystywane. –

Odpowiedz

0

Spróbuj:

p = Pool(4) 
for i in range(10): 
    input = np.random.rand(N) 
    p.apply_async(calculate, args=(input, matrix)) # perform function calculate as new process with arguments input and matrix 

p.close() 
p.join() # wait for all processes to complete 

Podejrzewam, że „częściowy” obiekt i mapa są w wyniku zachowania blokującym. (Chociaż ja nigdy nie używane częściowy, więc nie jestem z nim zapoznać.)

„apply_async” (lub „map_async”) są wieloprocesorowe metod, które specjalnie nie blokują - (patrz: Python multiprocessing.Pool: when to use apply, apply_async or map?)

Ogólnie , dla "kłopotliwych problemów równoległych", takich jak ten, apply_async działa dla mnie.

EDIT:

Mam tendencję do pisania wyniki do bazy danych MySQL, kiedy skończę - realizacja I, pod warunkiem nie działa, jeśli to nie jest twoje podejście. "map" jest prawdopodobnie właściwą odpowiedzią, jeśli chcesz użyć porządku na liście jako sposobu śledzenia, który wpis jest który, ale pozostaję podejrzany wobec "częściowych" obiektów.

Powiązane problemy