Multiprocessing.Pool: Когда использовать apply, apply_async или карту?

Я не видел четких примеров с примерами использования Pool.apply, Pool.apply_async и Pool.map. В основном я использую Pool.map; в чем преимущества других?

Ответ 1

В старые времена Python для вызова функции с произвольными аргументами вы использовали бы apply:

apply(f,args,kwargs)

apply все еще существует в Python2.7, но не в Python3, и, как правило, больше не используется. В настоящее время

f(*args,**kwargs)

является предпочтительным. Модули multiprocessing.Pool пытаются предоставить аналогичный интерфейс.

Pool.apply подобен Python apply, за исключением того, что вызов функции выполняется в отдельном процессе. Pool.apply блокирует до завершения функции.

Pool.apply_async также похож на Python встроенный apply, за исключением того, что вызов немедленно возвращается, а не ждет результата. Возвращается объект ApplyResult. Вы вызываете его метод get() для получения результата вызова функции. Метод get() блокирует до завершения функции. Таким образом, pool.apply(func, args, kwargs) эквивалентно pool.apply_async(func, args, kwargs).get().

В отличие от Pool.apply, метод Pool.apply_async также имеет обратный вызов, который, если он указан, вызывается, когда функция завершена. Это можно использовать вместо вызова get().

Например:

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

может дать результат, такой как

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

Обратите внимание, что в отличие от pool.map порядок результатов может не соответствовать порядку, в котором были сделаны вызовы Pool.apply_async.


Итак, если вам нужно запустить функцию в отдельном процессе, но хотите, чтобы текущий процесс блокировал, пока эта функция не вернется, используйте Pool.apply. Как Pool.apply, pool.map блокирует до тех пор, пока не будет возвращен полный результат.

Если вы хотите, чтобы пул рабочих процессов выполнял много вызовов функций асинхронно, используйте Pool.apply_async. порядок результатов не гарантированно будет таким же, как порядок вызовов Pool.apply_async.

Обратите внимание, что вы можете вызвать несколько разных функций с помощью Pool.apply_async (не для всех вызовов необходимо использовать одну и ту же функцию).

Напротив, pool.map применяет одну и ту же функцию ко многим аргументам. Однако, в отличие от Pool.apply_async, результаты возвращаются в порядке, соответствующем порядку аргументов.

Ответ 2

Относительно apply vs map:

pool.apply(f, args): f выполняется только в ОДИН из работников пула. Поэтому ОДИН из процессов в пуле будет работать f(args).

pool.map(f, iterable): этот метод прерывает итерацию в несколько фрагментов, которые он представляет в пул процессов как отдельные задачи. Таким образом, вы используете все процессы в пуле.