web-dev-qa-db-fra.com

multiprocessing.Pool: Quand utiliser apply, apply_async ou map?

Je n'ai pas vu d'exemples clairs avec des cas d'utilisation pour Pool.apply , Pool.apply_async et Pool.map . J'utilise principalement Pool.map; Quels sont les avantages des autres?

246
Phyo Arkar Lwin

À l'époque ancienne de Python, pour appeler une fonction avec des arguments arbitraires, vous utiliseriez apply:

apply(f,args,kwargs)

apply existe toujours dans Python2.7 mais pas dans Python3 et n'est généralement plus utilisé. Aujourd'hui,

f(*args,**kwargs)

est préféré. Les modules multiprocessing.Pool essaient de fournir une interface similaire.

Pool.apply ressemble à Python apply, sauf que l'appel de fonction est exécuté dans un processus séparé. Pool.apply bloque jusqu'à ce que la fonction soit terminée.

Pool.apply_async est également similaire à apply de Python, à l'exception que l'appel retourne immédiatement au lieu d'attendre le résultat. Un objet AsyncResult est renvoyé. Vous appelez sa méthode get() pour récupérer le résultat de l'appel de fonction. La méthode get() est bloquée jusqu'à ce que la fonction soit terminée. Ainsi, pool.apply(func, args, kwargs) est équivalent à pool.apply_async(func, args, kwargs).get().

Contrairement à Pool.apply, la méthode Pool.apply_async dispose également d'un rappel qui, s'il est fourni, est appelé à la fin de la fonction. Ceci peut être utilisé au lieu d'appeler get().

Par exemple:

import multiprocessing as mp
import time

def foo_pool(x):
    time.sleep(2)
    return x*x

result_list = []
def log_result(result):
    # This is called whenever foo_pool(i) returns a result.
    # result_list is modified only by the main process, not the pool workers.
    result_list.append(result)

def apply_async_with_callback():
    pool = mp.Pool()
    for i in range(10):
        pool.apply_async(foo_pool, args = (i, ), callback = log_result)
    pool.close()
    pool.join()
    print(result_list)

if __== '__main__':
    apply_async_with_callback()

peut donner un résultat tel que

[1, 0, 4, 9, 25, 16, 49, 36, 81, 64]

Notez que, contrairement à pool.map, l'ordre des résultats peut ne pas correspondre à l'ordre dans lequel les appels pool.apply_async ont été effectués.


Donc, si vous avez besoin d'exécuter une fonction dans un processus séparé, mais que vous voulez que le processus actuel soit block jusqu'au retour de cette fonction, utilisez Pool.apply. Comme Pool.apply, Pool.map bloque jusqu'au retour du résultat complet.

Si vous souhaitez que le pool de processus de travail effectue de nombreux appels de fonction de manière asynchrone, utilisez Pool.apply_async. L'ordre ordre des résultats n'est pas garanti identique à l'ordre des appels à Pool.apply_async.

Notez également que vous pouvez appeler plusieurs fonctions différentes avec Pool.apply_async (tous les appels ne doivent pas nécessairement utiliser la même fonction).

En revanche, Pool.map applique la même fonction à plusieurs arguments. Cependant, contrairement à Pool.apply_async, les résultats sont renvoyés dans un ordre correspondant à l'ordre des arguments.

369
unutbu

En ce qui concerne apply vs map:

pool.apply(f, args): f n'est exécuté que par UN des ouvriers du pool. Ainsi, UN des processus du pool exécutera f(args).

pool.map(f, iterable): cette méthode divise l'itéré en plusieurs morceaux qu'elle soumet au pool de processus en tant que tâches distinctes. Vous profitez donc de tous les processus du pool.

72
kakhkAtion