web-dev-qa-db-fra.com

Variable partagée dans le multiprocessing de python

La première question est quelle est la différence entre Value et Manager (). Value?

Deuxièmement, est-il possible de partager une variable entière sans utiliser Value? Voici mon exemple de code. Ce que je veux, c'est obtenir un dict avec une valeur entière, pas Value. Ce que j'ai fait, c'est de tout changer après le processus. Existe-t-il un moyen plus simple?

from multiprocessing import Process, Manager

def f(n):
    n.value += 1

if __name__ == '__main__':
    d = {}
    p = []

    for i in range(5):
        d[i] = Manager().Value('i',0)
        p.append(Process(target=f, args=(d[i],)))
        p[i].start()

    for q in p:
        q.join()

    for i in d:
        d[i] = d[i].value

    print d
25
user2435611

Lorsque vous utilisez Value vous obtenez un objet ctypes dans la mémoire partagée qui, par défaut, est synchronisé à l'aide de RLock . Lorsque vous utilisez Manager vous obtenez un objet SynManager qui contrôle un processus serveur qui permet aux valeurs d'objet d'être manipulées par d'autres processus. Vous pouvez créer plusieurs proxys en utilisant le même gestionnaire; il n'est pas nécessaire de créer un nouveau gestionnaire dans votre boucle:

manager = Manager()
for i in range(5):
    new_value = manager.Value('i', 0)

Manager peut être partagé entre plusieurs ordinateurs, tandis que Value est limité à un ordinateur. Value sera plus rapide (exécutez le code ci-dessous pour voir), donc je pense que vous devriez l'utiliser à moins que vous n'ayez besoin de prendre en charge des objets arbitraires ou d'y accéder via un réseau.

import time
from multiprocessing import Process, Manager, Value

def foo(data, name=''):
    print type(data), data.value, name
    data.value += 1

if __name__ == "__main__":
    manager = Manager()
    x = manager.Value('i', 0)
    y = Value('i', 0)

    for i in range(5):
        Process(target=foo, args=(x, 'x')).start()
        Process(target=foo, args=(y, 'y')).start()

    print 'Before waiting: '
    print 'x = {0}'.format(x.value)
    print 'y = {0}'.format(y.value)

    time.sleep(5.0)
    print 'After waiting: '
    print 'x = {0}'.format(x.value)
    print 'y = {0}'.format(y.value)

Pour résumer:

  1. Utilisez Manager pour créer plusieurs objets partagés, y compris des dict et des listes. Utilisez Manager pour partager des données entre les ordinateurs d'un réseau.
  2. Utilisez Value ou Array lorsqu'il n'est pas nécessaire de partager des informations sur un réseau et que les types dans ctypes sont suffisants pour vos besoins.
  3. Value est plus rapide que Manager.

Avertissement

Soit dit en passant, le partage des données entre les processus/threads doit être évité si possible. Le code ci-dessus s'exécutera probablement comme prévu, mais augmentez le temps nécessaire pour exécuter foo et les choses deviendront étranges. Comparez ce qui précède avec:

def foo(data, name=''):
    print type(data), data.value, name
    for j in range(1000):
        data.value += 1

Vous aurez besoin d'un Lock pour que cela fonctionne correctement.

Je ne suis pas particulièrement bien informé sur tout cela, alors peut-être que quelqu'un d'autre viendra et offrira plus d'informations. J'ai pensé que j'apporterais une réponse car la question n'attirait pas l'attention. J'espère que ça aide un peu.

31
ChrisP