0

J'ai une classe qui stocke un grand tableau numpy dans l'état. Cela provoque multiprocessing.Pool à devenir extrêmement lent. Voici un MRE:Multiprocessing avec grand tableau en état

from multiprocessing import Pool 
import numpy 
import time 
from tqdm import tqdm 

class MP(object): 
    def __init__(self, mat): 
     self.mat = mat 

    def foo(self, x): 
     time.sleep(1) 
     return x*x + self.mat.shape[0] 

    def bar(self, arr): 
     results = [] 
     with Pool() as p: 
      for x in tqdm(p.imap(self.foo, arr)): 
       results.append(x) 
     return results 

if __name__ == '__main__': 
    x = numpy.arange(8) 
    mat = numpy.random.random((1,1)) 
    h = MP(mat) 
    res = h.bar(x) 
    print(res) 

J'ai 4 cœurs sur CPU, ce qui signifie que ce code devrait (et ne) courir dans environ 2 secondes. (Le tqdm montre les 2 secondes comme une barre de progression, ce n'est pas vraiment nécessaire dans cet exemple). Cependant, dans le programme principal, si je fais mat = numpy.random.random((10000,10000)), il faut une éternité pour fonctionner. Je suppose que c'est parce que Pool fait des copies de mat pour chaque travailleur, mais je ne suis pas sûr comment cela fonctionne parce que mat est dans l'état de la classe, et non directement impliqué dans l'appel imap. Donc, mes questions sont:

  1. Pourquoi ce comportement se produit-il? (c'est-à-dire, comment Pool fonctionne-t-il dans une classe? Qu'est-ce qu'elle contient exactement? Quelles sont les copies effectuées et lesquelles sont transmises par référence?)
  2. Qu'est-ce qu'une solution de contournement viable à ce problème?

Modifier: modification foo à utiliser mat, qui est plus représentatif de mon vrai problème.

+0

Quelle est la taille de 'x' dans votre programme principal? –

+1

Dans votre programme principal, la fonction que vous transmettez à 'p.imap' doit-elle être une méthode de' MP', ou peut-elle être une fonction non liée? –

+0

@JeremyMcGibbon Bon point. Je suppose que mon exemple n'était pas une bonne représentation de mon vrai problème. Donc, la fonction doit être une méthode de 'MP', car la fonction lit réellement' mat'. – ved

Répondre

0

Si comme vous le dites mat est pas directement impliqué dans l'appel imap, je devine en général l'état de MP n'est pas utilisé dans l'appel imap (si elle est, commentaire ci-dessous et je vais supprimer cette réponse) . Si c'est le cas, vous devez écrire foo comme fonction non liée au lieu de MP. La raison mat est copié en ce moment parce que chaque exécution de foo doit être passée en self, qui contient self.mat.

Les exécute rapidement après quelle que soit la taille du tapis:

from multiprocessing import Pool 
import numpy 
import time 
from tqdm import tqdm 


class MP(object): 

    def __init__(self, mat): 
     self.mat = mat 

    def bar(self, arr): 
     results = [] 
     with Pool() as p: 
      for x in tqdm(p.imap(foo, arr)): 
       results.append(x) 
     return results 

def foo(x): 
    time.sleep(1) 
    return x * x 

if __name__ == '__main__': 
    x = numpy.arange(8) 
    mat = numpy.random.random((10000, 10000)) 
    h = MP(mat) 
    res = h.bar(x) 
    print(res) 

Si foo ne fait besoin d'être passé MP parce qu'il ne fait besoin de lire mat, alors il n'y a aucun moyen d'éviter d'envoyer mat à chaque processeur, et votre question 2 n'a pas de réponse autre que "vous ne pouvez pas". Mais j'espère avoir répondu à votre question 1.