python partager un set en mémoire

manager.set ?

a marqué ce sujet comme résolu.

hello, je trouve plusieurs exemple avec manager pour partager une liste entre plusieur processus, mais comment fait pour un set ?

en faite je n’ai pas besoin d’un set, mais une liste sans doublon, pour moi la logique voudrais que j’utilise un set.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from multiprocessing import Process, Manager

def worker(i):
    x[i].append(i)

if __name__ == '__main__':
    manager = Manager()
    x = manager.list()
    p = []

    for i in range(5):
        p.append(Process(target=worker, args=(i,)))
        p[i].start()

    print x

cela fonctionne bien, mais c’est une liste…donc j’ai des doublons

avec un set :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from multiprocessing import Process, Manager

def worker(i):
    x[i].add(i)

if __name__ == '__main__':
    manager = Manager()
    x = manager.set()
    p = []

    for i in range(5):
        p.append(Process(target=worker, args=(i,)))
        p[i].start()

    print x

naivement j’aurais pensé que cela fonctionnerais, mais manager ne reconnait pas ma structure : AttributeError: ’SyncManager’ object has no attribute ’set’

peut on partager en mémoire un set/ ou bien une liste sans doublon ?

+0 -0

Au passage, techniquement un set peut facilement être fait avec un dict : tu met tes éléments comme clés et tu met une constante, typiquement un singleton comme True, en valeur. Tu peux du coup facilement reproduire un set.

Ceci dit la véritable réponse dépend beaucoup de ce que tu compte faire. On en a parlé dans l’autre sujet, tu ferai mieux d’utiliser un Pool et map pour éviter de devoir gérer toi même les processus. Et au pire si tu as des doublons à la fin, tu peux toujours filtrer le résultat final.

Mais ça dépend beaucoup de l’application ! Il nous ferait plus de détail sur ton programme car le multiprocessing n’est pas simple. Ce ne sera pas la même chose si tu as quelques centaines de valeurs en résultat ou plusieurs millions. Cela ne sera pas la même chose si tu fais du calcul ou des io, etc.

Rien n’empêche d’utiliser une liste, non ?

fred1599

Ça n’est pas le même type de données (le set ne consiste pas qu’en l’unicité de ses éléments), et ça ouvre à des problèmes de concurrence.

entwanne

Merci du renseignement, mais le problème ici, c’est pas l’unicité des éléments justement ?

Quand tu parles de problèmes de concurrence, tu peux être plus précis?

J’ai étudié un peu les dict et effectivement pourrais me convenir.

@Kje Pour le pool, on peut partager une variable avec ? d’après ce que j’ai vue dans la doc on ne peut envoyer qu’un argument dans une fonction avec un pool (une liste plus précisément) Moi il me faut envoyer 2 arguments, le dict.manager et ma donné à traiter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def worker(n, d):
    d[n] = True

if __name__ == '__main__':
        manager = Manager()
        d = manager.dict()


        data=["chaine1", "chaine2"]
        p = Pool(2)
        p.map(worker, data)

`

comment je partage mon dict ?

Quand tu parles de problèmes de concurrence, tu peux être plus précis?

fred1599

Entre le moment où tu testes l’appartenance et celui où tu insères l’élément, un autre processus peut opérer et insérer le même élément, ce qui provoquera justement un doublon.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import random
from multiprocessing import Manager, Pool
from collections import Counter

def worker(data):
    n = random.randint(0, 10)
    if n not in data:
        data.append(n)

with Manager() as manager:
    data = manager.list()
    with Pool(5) as pool:
        pool.map(worker, [data]*100)
    print(Counter(data))

Avec ce code, j’obtiens des résultats comme :

1
Counter({8: 2, 0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 9: 1, 10: 1})

Ceci dit la véritable réponse dépend beaucoup de ce que tu compte faire. On en a parlé dans l’autre sujet, tu ferai mieux d’utiliser un Pool et map pour éviter de devoir gérer toi même les processus. Et au pire si tu as des doublons à la fin, tu peux toujours filtrer le résultat final.

Kje

L’« autre sujet » n’est pas du même auteur. :-°

@entwanne, de toute manière vous ne réglé pas le principal problème, comment j’envoie votre variable n dans la fonction worker en plus de data ?

mathema

Parce que je m’adressais à fred1599 pour évoquer le soucis avec la concurrence.

Je ne connais pas très bien multiprocessing, mais tu devrais pouvoir régler ton histoire de multiples arguments avec starmap qui est fait pour ça.

1
2
3
4
5
6
7
import multiprocessing

def worker(x, y):
    return x + y

with multiprocessing.Pool(5) as pool:
    pool.starmap(worker, zip(range(5), range(5)))

Après, si tu n’as pas l’utilité des valeurs de retour de tes workers, il est sûrement préférable d’utiliser des apply_async.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import multiprocessing

def worker(data, n):
    data.append(n)

with multiprocessing.Manager() as manager:
    data = manager.list()
    with multiprocessing.Pool(5) as pool:
        results = [pool.apply_async(worker, (data, i)) for i in range(5)]
        for res in results:
            res.wait()
    print(data)

@mathema : Il est facilement possible de passer plusieurs arguments mais c’est pas si évident que tu en ai besoin. Je vais reformuler ma question : Que veux tu mettre dans ton set ? Est-ce que tu traite vraiment tant de valeurs que ça qui fait que passer par un map et faire un post-traitement ne serait pas suffisant ?

Exemple :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from multiprocessing import Pool
import itertools

def worker(v):
    a1, a2 = v
    return a1 + a2

if __name__ == '__main__':
    p = Pool(2)
    result_list = p.map(worker, itertools.product(range(25), range(25)))
    result = set(result_list)

C’est la façon de faire la plus simple et la plus sûrs

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