web-dev-qa-db-fra.com

python MultiProcessing de sous-classement.Processing

Je suis nouveau à python objet orienté et je réécrit mon application existante en tant que version orientée objet, car les développeurs sont en augmentation et que mon code est en train de devenir non sécurisé.

Normalement, j'utilise des files d'attente multiprocessionnaires, mais j'ai trouvé à partir de cet exemple http://www.doughellmann.com/pymotw/multiprorocessing/basics.html que je peux sous-classement multiprocessing.Process Alors je pense que c'est un Bonne idée et j'ai écrit une classe à tester comme ceci:

code:

from multiprocessing import Process
class Processor(Process):
    def return_name(self):
        return "Process %s" % self.name
    def run(self):
        return self.return_name()

processes = []


if __name__ == "__main__":

        for i in range(0,5):
                p=Processor()
                processes.append(p)
                p.start()
        for p in processes:
                p.join()

Cependant, je ne peux pas récupérer les valeurs, comment puis-je utiliser des files d'attente de cette manière?

Edit: Je veux obtenir la valeur de retour et penser où mettre Queues().

26
Phyo Arkar Lwin

Sous-classement multiprocessing.Process:

Cependant, je ne peux pas récupérer les valeurs, comment puis-je utiliser des files d'attente de cette manière?

Le processus nécessite une Queue() pour recevoir les résultats ... Un exemple de la sous-classe multiprocessing.Process Suit ...

from multiprocessing import Process, Queue
class Processor(Process):

    def __init__(self, queue, idx, **kwargs):
        super(Processor, self).__init__()
        self.queue = queue
        self.idx = idx
        self.kwargs = kwargs

    def run(self):
        """Build some CPU-intensive tasks to run via multiprocessing here."""
        hash(self.kwargs) # Shameless usage of CPU for no gain...

        ## Return some information back through multiprocessing.Queue
        ## NOTE: self.name is an attribute of multiprocessing.Process
        self.queue.put("Process idx={0} is called '{1}'".format(self.idx, self.name))

if __name__ == "__main__":
    NUMBER_OF_PROCESSES = 5

    ## Create a list to hold running Processor object instances...
    processes = list()

    q = Queue()  # Build a single queue to send to all process objects...
    for i in range(0, NUMBER_OF_PROCESSES):
        p=Processor(queue=q, idx=i)
        p.start()
        processes.append(p)

    # Incorporating ideas from this answer, below...
    #    https://stackoverflow.com/a/42137966/667301
    [proc.join() for proc in processes]
    while not q.empty():
        print "RESULT: {0}".format(q.get())   # get results from the queue...

Sur ma machine, cela se traduit par ...

$ python test.py
RESULT: Process idx=0 is called 'Processor-1'
RESULT: Process idx=4 is called 'Processor-5'
RESULT: Process idx=3 is called 'Processor-4'
RESULT: Process idx=1 is called 'Processor-2'
RESULT: Process idx=2 is called 'Processor-3'
$


En utilisant multiprocessing.Pool:

FWIW, un désavantage que j'ai trouvé au sous-classement multiprocessing.Process Est que vous ne pouvez pas tirer parti de toute la bonté intégrée de multiprocessing.Pool; Pool vous donne une très belle API si vous ne le faites pas besoin votre producteur et votre code de consommateur à se parler à une file d'attente.

Vous pouvez faire beaucoup de choses avec quelques valeurs de retour créatives ... dans l'exemple suivant, j'utilise une dict() pour encapsuler les valeurs d'entrée et de sortie de pool_job()...

from multiprocessing import Pool

def pool_job(input_val=0):
    # FYI, multiprocessing.Pool can't guarantee that it keeps inputs ordered correctly
    # dict format is {input: output}...
    return {'pool_job(input_val={0})'.format(input_val): int(input_val)*12}

pool = Pool(5)  # Use 5 multiprocessing processes to handle jobs...
results = pool.map(pool_job, xrange(0, 12)) # map xrange(0, 12) into pool_job()
print results

Il en résulte:

[
    {'pool_job(input_val=0)': 0}, 
    {'pool_job(input_val=1)': 12}, 
    {'pool_job(input_val=2)': 24}, 
    {'pool_job(input_val=3)': 36}, 
    {'pool_job(input_val=4)': 48}, 
    {'pool_job(input_val=5)': 60}, 
    {'pool_job(input_val=6)': 72}, 
    {'pool_job(input_val=7)': 84}, 
    {'pool_job(input_val=8)': 96}, 
    {'pool_job(input_val=9)': 108}, 
    {'pool_job(input_val=10)': 120}, 
    {'pool_job(input_val=11)': 132}
]

De toute évidence, il y a beaucoup d'autres améliorations à apporter dans pool_job(), telle que la manipulation des erreurs, mais cela illustre l'essentiel. FYI, Cette réponse Fournit un autre exemple de comment utiliser multiprocessing.Pool.

36
Mike Pennington

Merci beaucoup tout le monde.

Maintenant, voici comment je l'ai fait :)

Dans cet exemple, j'utilise plusieurs Queus, car je ne veux pas communiquer entre chaque Ohter, mais uniquement avec le processus parent.

from multiprocessing import Process,Queue
class Processor(Process):
    def __init__(self,queue):
        Process.__init__(self)
        self.que=queue
    def get_name(self):
        return "Process %s" % self.name
    def run(self):
        self.que.put(self.get_name())



if __name__ == "__main__":

        processes = []
        for i in range(0,5):
                p=Processor(Queue())
                processes.append(p)
                p.start()
        for p in processes:
                p.join()
                print p.que.get()
2
Phyo Arkar Lwin

La valeur de retour de Process.run ne va nulle part. Vous devez les renvoyer au processus parent, par exemple. utilisant un multiprocessing.Queue ( docs ici ).

2
Thomas K

Réponse de Mike est le meilleur, mais juste pour la complétude, je veux mentionner que je préfère Récupérez la file d'attente de join contextes Donc, le dernier bit ressemblerait à ceci:

[proc.join() for proc in processes] # 1. join

while not q.empty(): # 2. get the results
    print "RESULT: %s" % q.get()
2
Lorah Attkins