Existem duas diferenças principais entre imap
/ imap_unordered
e map
/ map_async
:
- A maneira como eles consomem o iterável que você passa para eles.
- A maneira como eles retornam o resultado para você.
map
consome seu iterável convertendo o iterável em uma lista (supondo que não seja uma lista já), dividindo-o em pedaços e enviando-os para os processos de trabalho no diretório Pool
. Quebrar o iterável em partes tem um desempenho melhor do que passar cada item no iterável entre processos, um item de cada vez - principalmente se o iterável for grande. No entanto, transformar o iterável em uma lista para fragmentá-lo pode ter um custo de memória muito alto, pois a lista inteira precisará ser mantida na memória.
imap
não transforma o iterável que você colocou em uma lista, nem o divide em partes (por padrão). Ele iterará sobre o elemento iterável por vez e os enviará para um processo de trabalho. Isso significa que você não leva o hit de memória de converter o iterável inteiro para uma lista, mas também significa que o desempenho é mais lento para iterables grandes, devido à falta de chunking. Isso pode ser atenuado passando um chunksize
argumento maior que o padrão de 1, no entanto.
A outra grande diferença entre imap
/ imap_unordered
e map
/ map_async
é que, com imap
/ imap_unordered
, você pode começar a receber resultados dos trabalhadores assim que eles estiverem prontos, em vez de esperar que todos eles sejam concluídos. Com map_async
, um AsyncResult
é retornado imediatamente, mas você não pode recuperar os resultados desse objeto até que todos eles tenham sido processados; nesse momento, ele retorna a mesma lista que map
faz ( map
é realmente implementado internamente como map_async(...).get()
). Não há como obter resultados parciais; você tem o resultado inteiro ou nada.
imap
e imap_unordered
ambos retornam iterables imediatamente. Com imap
, os resultados serão gerados a partir do iterável assim que estiverem prontos, preservando ainda a ordenação da entrada iterável. Com imap_unordered
, os resultados serão gerados assim que estiverem prontos, independentemente da ordem da entrada iterável. Então, diga que você tem isso:
import multiprocessing
import time
def func(x):
time.sleep(x)
return x + 2
if __name__ == "__main__":
p = multiprocessing.Pool()
start = time.time()
for x in p.imap(func, [1,5,3]):
print("{} (Time elapsed: {}s)".format(x, int(time.time() - start)))
Isso produzirá:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Se você usar em p.imap_unordered
vez de p.imap
, verá:
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
Se você usar p.map
ou p.map_async().get()
, verá:
3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Portanto, os principais motivos para usar imap
/ imap_unordered
over map_async
são:
- Seu iterável é grande o suficiente para convertê-lo em uma lista, causando a falta / uso de muita memória.
- Você deseja iniciar o processamento dos resultados antes que todos eles sejam concluídos.
apply
envia uma única tarefa para um processo de trabalho e depois bloqueia até que seja concluída.apply_async
envia uma única tarefa para um processo de trabalho e retorna imediatamente umAsyncResult
objeto, que pode ser usado para aguardar a conclusão da tarefa e recuperar o resultado.apply
é implementado simplesmente chamandoapply_async(...).get()
Pool
documentação oficial , e não na documentação monótona existente .