багатопроцесорна робота. Басейн: в чому різниця між map_async та imap?


184

Я намагаюся навчитися використовувати multiprocessingпакет Python , але я не розумію різниці між map_asyncі imap. Я помітив, що обидва map_asyncі imapвиконуються асинхронно. Отже, коли я повинен використовувати один над іншим? І як мені отримати результат, повернутий map_async?

Чи варто використовувати щось подібне?

def test():
    result = pool.map_async()
    pool.close()
    pool.join()
    return result.get()

result=test()
for i in result:
    print i

Відповіді:


492

Існує дві ключові відмінності між imap/ imap_unorderedі map/ map_async:

  1. Те, як вони споживають ітерабельне, ви їм передаєте.
  2. Те, як вони повернуть вам результат.

mapспоживає ваш ітерабельний, перетворюючи ітерабельний у список (припускаючи, що це вже не список), розбиваючи його на шматки та відправляючи ці шматки робочим процесам у Pool. Розбивання ітерабельної частини на кращі ефективніше, ніж передача кожного елемента в ітерабельному режимі між процесами по одному предмету, особливо, якщо ітерабельний обсяг великий. Однак перетворення ітерабельного списку в цілий список може мати дуже високу вартість пам'яті, оскільки весь список потрібно буде зберігати в пам'яті.

imapне перетворює ітерабельний ви даєте його до списку, а також не розбиває на шматки (за замовчуванням). Він повторюватиме одночасно один ітерабельний елемент та надсилатиме їх кожному робочому процесу. Це означає, що ви не приймаєте хіт пам'яті, щоб перетворити весь ітерабельний список у список, але це також означає, що для великих ітерабелів продуктивність працює повільніше, через відсутність чутливості. Однак це можна пом'якшити, передавши chunksizeаргумент, більший за замовчуванням на 1.

Інша основна відмінність між imap/ imap_unorderedі map/ map_asyncполягає в тому, що з imap/ imap_unorderedви можете починати отримувати результати від працівників, як тільки вони будуть готові, а не потрібно чекати, коли всі вони закінчаться. З map_async, а AsyncResultповертається одразу, але ви не можете фактично отримати результати з цього об’єкта, поки всі вони не будуть оброблені, і в цей момент він повертає той самий список, що mapі mapє ( насправді реалізований внутрішньо як map_async(...).get()). Немає можливості отримати часткові результати; у вас або весь результат, або нічого.

imapі imap_unorderedобидва повертають ітерабелі відразу. З imap, результати будуть отримані з ітерабельного, як тільки вони будуть готові, при цьому зберігаючи впорядкованість вхідних ітерабельних. З imap_unordered, результати будуть отримані, як тільки вони будуть готові, незалежно від порядку введення даних. Отже, скажіть, у вас це є:

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)))

Це виведе:

3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)

Якщо ви використовуєте p.imap_unorderedзамість p.imap, ви побачите:

3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)

Якщо ви використовуєте p.mapабо p.map_async().get(), ви побачите:

3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)

Отже, основними причинами використання imap/ imap_unorderedнадходження map_asyncє:

  1. Ваш ітерабельний файл достатньо великий, що перетворення його до списку призведе до того, що у вас вичерпається / не буде використано занадто багато пам'яті.
  2. Ви хочете , щоб мати можливість почати обробку результатів , перш ніж всі вони будуть завершені.

1
а як застосувати і apply_async?
Суворий Дафтарі

10
@HarshDaftary applyвідсилає одне завдання робочому процесу, а потім блокує, поки воно не завершиться. apply_asyncвідправляє одне завдання в робочий процес, а потім негайно повертає AsyncResultоб'єкт, який можна використовувати для очікування завершення завдання та отримання результату. applyреалізується просто зателефонувавшиapply_async(...).get()
dano

51
Ось такий опис, який повинен бути в офіційній Poolдокументації, а не в існуючій тупий .
хвилини

@dano Я хочу запустити функцію у фоновому режимі, але у мене є деякі обмеження ресурсів, і я не можу запустити функцію стільки разів, скільки мені хочеться, і я хочу поставити в чергу чергові виконання функції. Чи маєте ви якесь уявлення про те, як мені це зробити? У мене тут питання . Чи можете ви, будь ласка, поглянути на моє запитання і побачити, чи можете ви дати мені підказки (а ще краще, відповідь) про те, як я повинен це зробити?
Амір

1
@BallpointBen Перейдемо до наступного твору, як тільки це буде зроблено. Замовлення обробляється назад у батьківському процесі.
dano
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.