python pool.map partager une liste

a marqué ce sujet comme résolu.

Bonjour, question simple mais réponse pas si simple. Je veut lancer une fonction sur 4 coeur qui sauvegarde des résulats dans une matrice 2D

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import multiprocessing

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

matrix=[[],[]]
def myfunc(p):
    print(p)
    matrix[0].append(p[0]+p[1])
    matrix[1].append(p[0]*p[1])
    return p[0]

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    result_list = pool.map(myfunc, data_pairs)
    print(result_list)

    print(matrix)

Mon problème c’est que ma fonction n’ajoute pas les données à ma matrice matrix je pense que c’est une histoire de partage mémoire, le processus python n’a pas accès à matrix qui est dans un autre processus. d’ou ma question, comment partager ma variable matrix.

j’ai le meme probleme avec un mananger.list :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import multiprocessing
from multiprocessing import Manager

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

def myfunc(p):
    print(p)
    matrix[0].append(p[0]+p[1])
    matrix[1].append(p[0]*p[1])
    return p[0]

if __name__ == '__main__':
    manager = Manager()
    matrix = manager.list([[],[]])

    pool = multiprocessing.Pool(processes=4)
    result_list = pool.map(myfunc, data_pairs)
    print(result_list)

    print(matrix)

    numbers = sum([len(part) for part in matrix])
    print(numbers)

Hello! Petite précision :

Je veut lancer une fonction sur 4 coeur qui sauvegarde des résulats dans une matrice 2D

jipete

À cause du Global Interpreter Lock, tu n’auras de toute façon qu’un seul thread exécuté à la fois. Donc que tu aies un coeur, deux coeurs ou bien quatre… Je suis désolé de te décevoir, mais ça ne changera rien.

Si tu tiens vraiment à faire du parallélisme sur Python, tu peux peut-être voir du côté de cython ou te pencher sur les sub-interpreters… Mais j’ai des doutes que la dernière solution te permette de partager de la mémoire aussi efficacement. Je connais très mal le sujet, après.

A+

+0 -1

d’apres ce que j’ai trouvé, je dois mettre matrix en paramètre de fonction, mais les code que je trouve ne marche pas

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import multiprocessing
from multiprocessing import Manager
from itertools import product
from functools import partial

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

def myfunc(p, matrix):
    print(p)
    matrix[0].append(p[0]+p[1])
    matrix[1].append(p[0]*p[1])
    return p[0]

if __name__ == '__main__':
    manager = Manager()
    matrix = manager.list([[],[]])

    pool = multiprocessing.Pool(processes=4)
    #result_list = pool.map(myfunc, product(data_pairs, matrix))
    result_list = pool.map(partial(myfunc, matrix), data_pairs)
    print(result_list)

    print(matrix)

    numbers = sum([len(part) for part in matrix])
    print(numbers)

Par « ne marche pas », tu veux dire qu’il y a une erreur ?

Parce que je vois plusieurs soucis dans le code que tu donnes :

  • Les paramètres de myfunc sont inversés. L’utilisation de partial fait que c’est la valeur de matrix qui sera donnée en premier.
  • Les sous-listes de matrix devraient aussi être gérées par le manager, sinon tu retomberas sur les mêmes problèmes que précédemment (matrix = manager.list(manager.list([manager.list(), manager.list()]))).

Merci pour ton aide entwanne j’ai un "index out of range" quand je fait mes append sur matrix

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import multiprocessing
from multiprocessing import Manager
from itertools import product
from functools import partial

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

def myfunc(p, matrix):
    print(p)
    matrix[0].append(0)
    matrix[1].append(1)
    return p[0]

if __name__ == '__main__':
    manager = Manager()
    matrix = manager.list(manager.list([manager.list(), manager.list()]))

    pool = multiprocessing.Pool(processes=4)
    #result_list = pool.map(myfunc, product(data_pairs, matrix))
    result_list = pool.map(partial(myfunc, data_pairs), matrix)

En effet (mais la prochaine fois essaie d’être plus précis sur l’erreur, avec un traceback plus complet).

Tu utilises pool.map, sais-tu bien pour quelle raison ? A priori, tu cherchais à diviser le travail sur la liste data_pairs, et donc à faire en sorte que chaque worker prenne en charge un élément de la liste. Dans ce cas, c’est data_pairs qui doit être le second argument passé à map, pas matrix.

Dans le fonctionnement actuel, tu crées un worker pour chaque élément de matrix, liste de deux éléments, ce qui explique le problème.

Au passage, j’ai fait une erreur dans mon précédent post, il y a un manager.list inutile.

meme la j’ai toujours pas de matrix[1]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import multiprocessing
from multiprocessing import Manager
from itertools import product
from functools import partial

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

def myfunc(p, matrix):
    #print(p)
    matrix[0].append(0)
    matrix[1].append(1)
    return p[0]

if __name__ == '__main__':
    manager = Manager()
    matrix = manager.list([(manager.list(), manager.list())])

    pool = multiprocessing.Pool(processes=4)
    result_list = pool.map(partial(myfunc, data_pairs), matrix)
    print(result_list)

    print(matrix[0][0])
    print(matrix[1][0])

    numbers = sum([len(part) for part in matrix])
    print(numbers)

matrix[1][0] m’affiche index out of range. pourtant il y’a bien 2 élements dans ma matrix.

Déjà, comme je te l’ai dit, ce n’est pas matrix que tu dois utiliser comme second paramètre de pool.map.

Ensuite, si tu regardes ta définition de matrix, tu peux remarquer que c’est une liste managée composée d’un seul élément, un tuple, lui même composé de deux listes managées.

Ordonne correctement tes arguments et paramètres, supprime ce tuple et tout ira bien.

tu est sur ? car quand j’inverse mes parametres j’ai une erreur avec matrix[0].append(0)

AttributeError: ’int’ object has no attribute ’append’

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import multiprocessing
from multiprocessing import Manager
from itertools import product
from functools import partial

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

def myfunc(p, matrix):
    #print(p)
    matrix[0].append(0)
    matrix[1].append(1)
    return p[0]

if __name__ == '__main__':
    manager = Manager()
    matrix = manager.list([(manager.list(), manager.list())])

    pool = multiprocessing.Pool(processes=4)
    result_list = pool.map(partial(myfunc, matrix), data_pairs)
    print(result_list)

    print(matrix[0][0])
    print(matrix[1][0])

    numbers = sum([len(part) for part in matrix])
    print(numbers)
+0 -0

a merci sa marche, le code final :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import multiprocessing
from multiprocessing import Manager
from itertools import product
from functools import partial

data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]

def myfunc(matrix, p):
    #print(p)
    matrix[0].append(0)
    matrix[1].append(1)
    return p[0]

if __name__ == '__main__':
    manager = Manager()
    matrix = manager.list([manager.list(), manager.list()])

    pool = multiprocessing.Pool(processes=4)
    result_list = pool.map(partial(myfunc, matrix), data_pairs)
    print(result_list)

    print(matrix[0])
    print(matrix[1])

    numbers = sum([len(part) for part in matrix])
    print(numbers)

je sais pas si c’est possible de le faire den python (la doc est plutôt négative sur ce sujet), mais est t’il possible d’intégrer mon code dans un objet python ?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import multiprocessing
from multiprocessing import Manager
from itertools import product
from functools import partial

class Data():

    def __init__(self):
        self.manager = Manager()
        self.matrix = self.manager.list([self.manager.list(), self.manager.list()])
        self.data_pairs = [ [3,5], [4,3], [7,3], [1,6] ]
        self.result_list=[]

    def myfunc(self, p):
        #print(p)
        self.matrix[0].append(0)
        self.matrix[1].append(1)
        return p[0]

    def start_algo(self):
        pool = multiprocessing.Pool(processes=4)
        self.result_list = pool.map(partial(self.myfunc, self.matrix), self.data_pairs)


if __name__ == '__main__':
    data=Data()
    data.start_algo()
    print(data.matrix)

j’ai cette erreur :

1
TypeError: Pickling an AuthenticationString object is disallowed for security reasons

Ça me semble être une mauvaise manière de procéder.

Il faut bien comprendre que multiprocessing fonctionne en envoyant des données sérialisées (pickle) d’un processus à l’autre (ou avec des mémoires partagées). Donc le plus simple peuvent être les données échangées, le mieux ce sera.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte