1

J'essaie d'exploiter concurrent.futures.ProcessPoolExecutor dans Python3 pour traiter une grande matrice en parallèle. La structure générale du code est:Pourquoi les performances de concurrent.futures.ProcessPoolExecutor sont-elles très faibles?

class X(object): 

self.matrix 

def f(self, i, row_i): 
    <cpu-bound process> 

def fetch_multiple(self, ids): 
    with ProcessPoolExecutor() as executor: 
     futures = [executor.submit(self.f, i, self.matrix.getrow(i)) for i in ids] 
     return [f.result() for f in as_completed(futures)] 

self.matrix est un grand scipy csr_matrix. f est ma fonction concurrente qui prend une ligne de self.matrix et applique un processus lié au processeur. Enfin, fetch_multiple est une fonction qui exécute plusieurs instances de f en parallèle et renvoie les résultats.

Le problème est que, après l'exécution du script, tous les cœurs cpu sont moins de 50% d'occupation (Voir la capture d'écran suivante):

enter image description here

Pourquoi tous les cœurs ne sont pas occupés?

Je pense que le problème est le gros objet de self.matrix et le passage des vecteurs de ligne entre les processus. Comment puis-je résoudre ce problème?

Répondre

1

Oui. Le surcoût ne devrait pas être si grand - mais il est probable que vos processeurs apparaissent en attente (bien qu'ils devraient être occupés à transmettre les données de toute façon).

Mais essayez la recette ici pour passer un "pointeur" de l'objet au sous-processus en utilisant la mémoire partagée.

http://briansimulator.org/sharing-numpy-arrays-between-processes/

Je cite là:

from multiprocessing import sharedctypes 
size = S.size 
shape = S.shape 
S.shape = size 
S_ctypes = sharedctypes.RawArray('d', S) 
S = numpy.frombuffer(S_ctypes, dtype=numpy.float64, count=size) 
S.shape = shape 

Maintenant, nous pouvons envoyer S_ctypes et la forme à un processus enfant dans multitraitement, et reconvertir en un tableau numpy dans le processus enfant comme suit:

from numpy import ctypeslib 
S = ctypeslib.as_array(S_ctypes) 
S.shape = shape 

Il devrait être difficile de prendre en compte le comptage des références, mais je suppose que numpy.ctypeslib s'occupe de cela - donc, il suffit de coordonner le passage du numéro de ligne réel aux sous-processus d'une manière qui ne fonctionne pas sur les mêmes données