multiprocessing.Pool: quando utilizzare apply, apply_async o map?


Risposte:


424

Ai vecchi tempi di Python, per chiamare una funzione con argomenti arbitrari, avresti usato apply:

apply(f,args,kwargs)

applyesiste ancora in Python2.7 sebbene non in Python3 e generalmente non viene più utilizzato. Al giorno d'oggi,

f(*args,**kwargs)

è preferito. I multiprocessing.Poolmoduli tenta di fornire un'interfaccia simile.

Pool.applyè come Python apply, tranne per il fatto che la chiamata di funzione viene eseguita in un processo separato. Pool.applysi blocca fino al completamento della funzione.

Pool.apply_asyncè anche come integrato in Python apply, tranne per il fatto che la chiamata ritorna immediatamente invece di attendere il risultato. Viene AsyncResultrestituito un oggetto. Si chiama il suo get()metodo per recuperare il risultato della chiamata di funzione. Il get()metodo si blocca fino al completamento della funzione. Pertanto, pool.apply(func, args, kwargs)equivale a pool.apply_async(func, args, kwargs).get().

Al contrario Pool.apply, il Pool.apply_asyncmetodo ha anche un callback che, se fornito, viene chiamato quando la funzione è completa. Questo può essere usato invece di chiamare get().

Per esempio:

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 __name__ == '__main__':
    apply_async_with_callback()

può dare un risultato come

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

Si noti, a differenza pool.map, l'ordine dei risultati potrebbe non corrispondere all'ordine in cui pool.apply_asyncsono state effettuate le chiamate.


Pertanto, se è necessario eseguire una funzione in un processo separato, ma si desidera bloccare il processo corrente fino a quando tale funzione non viene restituita, utilizzare Pool.apply. Ad esempio Pool.apply, Pool.mapblocca fino a quando non viene restituito il risultato completo.

Se si desidera che il pool di processi di lavoro esegua molte chiamate di funzione in modo asincrono, utilizzare Pool.apply_async. L' ordine dei risultati non è garantito essere uguale all'ordine delle chiamate a Pool.apply_async.

Si noti inoltre che è possibile chiamare diverse funzioni con Pool.apply_async(non tutte le chiamate devono utilizzare la stessa funzione).

Al contrario, Pool.mapapplica la stessa funzione a molti argomenti. Tuttavia, a differenza Pool.apply_asyncdei risultati, i risultati vengono restituiti in un ordine corrispondente all'ordine degli argomenti.


11
Dovrebbe esserci if __name__=="__main__"prima apply_async_with_callback()su Windows?
jfs

3
Molte grazie. che ne dici di map_async?
Phyo Arkar Lwin il

38
Guarda dentro multiprocessing / pool.py e vedrai che Pool.map(func,iterable)è equivalente a Pool.map_async(func,iterable).get(). Quindi la relazione tra Pool.mape Pool.map_asyncè simile a quella di Pool.applye Pool.apply_async. I asynccomandi ritornano immediatamente, mentre i non- asynccomandi si bloccano. I asynccomandi hanno anche un callback.
unutbu,

7
Decidere se usare Pool.maped Pool.applyè simile a decidere quando usare mapo applyin Python. Basta usare lo strumento adatto al lavoro. La decisione tra l'utilizzo della versione asyncnon e asyncdipende dalla richiesta della chiamata per bloccare il processo corrente e / o dalla possibilità di utilizzare la richiamata.
unutbu,

6
@falsePockets: Sì. Ogni chiamata a apply_asyncrestituisce un ApplyResultoggetto. Chiamata che ApplyResult's getmetodo restituirà il valore di ritorno della funzione associata (o rilancio mp.TimeoutErrorse i tempi-out. Di chiamata) Quindi, se si mettono le ApplyResults in un elenco ordinato, quindi chiamando i loro getmetodi restituirà i risultati nello stesso ordine. pool.mapTuttavia, potresti semplicemente utilizzare in questa situazione.
unutbu,

75

Per quanto riguarda applyvs map:

pool.apply(f, args): fviene eseguito solo in UNO dei lavoratori della piscina. Quindi, uno dei processi nel pool verrà eseguito f(args).

pool.map(f, iterable): Questo metodo taglia l'iterabile in un numero di blocchi che invia al pool di processi come attività separate. Quindi approfitti di tutti i processi nel pool.


4
cosa succede se l'iterabile è un generatore
RustyShackleford il

Hmm ... Buona domanda. A dire il vero non ho mai piscine con generatori usati, ma questa discussione potrebbe essere utile: stackoverflow.com/questions/5318936/...
kakhkAtion

@kakhkAtion Per quanto riguarda si applicano, se solo uno dei lavoratori esegue la funzione, cosa fanno gli altri lavoratori? Devo chiamare più volte per fare in modo che il resto dei lavoratori esegua un'attività?
Moondra,

3
Vero. Dai anche un'occhiata a pool.apply_async se vuoi pranzare i lavoratori in modo asincrono. "pool_apply blocca fino a quando il risultato non è pronto, quindi apply_async () è più adatto per eseguire lavori in parallelo"
kakhkAzione

1
Cosa succede quando ho 4 processi ma ho chiamato apply_async()8 volte? Lo gestirà automaticamente con una coda?
Saravanabalagi Ramachandran,

31

Ecco una panoramica in un formato tabella per mostrare le differenze tra Pool.apply, Pool.apply_async, Pool.mape Pool.map_async. Quando ne scegli uno, devi prendere in considerazione multi-arg, concorrenza, blocco e ordini:

                  | Multi-args   Concurrence    Blocking     Ordered-results
---------------------------------------------------------------------
Pool.map          | no           yes            yes          yes
Pool.map_async    | no           yes            no           yes
Pool.apply        | yes          no             yes          no
Pool.apply_async  | yes          yes            no           no
Pool.starmap      | yes          yes            yes          yes
Pool.starmap_async| yes          yes            no           no

Appunti:

  • Pool.imape Pool.imap_async- versione più pigra di map e map_async.

  • Pool.starmap metodo, molto simile al metodo cartografico oltre all'accettazione di più argomenti.

  • Asynci metodi inviano tutti i processi contemporaneamente e recuperano i risultati al termine. Utilizzare il metodo get per ottenere i risultati.

  • Pool.map(o Pool.apply) i metodi sono molto simili alla mappa (o applica) integrata di Python. Bloccano il processo principale fino al completamento di tutti i processi e restituiscono il risultato.

Esempi:

carta geografica

Viene chiamato per un elenco di lavori in una volta

results = pool.map(func, [1, 2, 3])

applicare

Può essere chiamato solo per un lavoro

for x, y in [[1, 1], [2, 2]]:
    results.append(pool.apply(func, (x, y)))

def collect_result(result):
    results.append(result)

map_async

Viene chiamato per un elenco di lavori in una volta

pool.map_async(func, jobs, callback=collect_result)

apply_async

Può essere chiamato solo per un lavoro ed esegue un lavoro in background in parallelo

for x, y in [[1, 1], [2, 2]]:
    pool.apply_async(worker, (x, y), callback=collect_result)

Starmap

È una variante di pool.mapcui supporta più argomenti

pool.starmap(func, [(1, 1), (2, 1), (3, 1)])

starmap_async

Una combinazione di starmap () e map_async () che scorre su iterabili di iterabili e chiama funzioni con iterabili decompressi. Restituisce un oggetto risultato.

pool.starmap_async(calculate_worker, [(1, 1), (2, 1), (3, 1)], callback=collect_result)

Riferimento:

Trova la documentazione completa qui: https://docs.python.org/3/library/multiprocessing.html


2
Pool.starmap () sta bloccando
Alan Evangelista il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.