Предотвращение копирования словаря при использовании pool.map () - PullRequest
0 голосов
/ 04 марта 2019

У меня есть функция f(x) Я хочу оценить список значений xrange параллельно.Функция делает что-то вроде этого:

def f(x, wrange, dict1, dict2):

    out_list = []

    v1 = dict1[x]

    for w in wrange:
        v2 = dict2[x-w]
        out_list += [np.dot(v1, v2)]

    return out_list

, она принимает значения матрицы из словаря dict1, вектор из словаря dict2, затем умножает их вместе.Теперь мой обычный подход для параллельного выполнения этого будет выглядеть примерно так:

import functools
import multiprocessing

par_func = functools.partial(f, wrange=wrange, dict1=dict1, dict2=dict2)

p = multiprocessing.Pool(4)
ssdat = p.map(par_func, wrange)
p.close()
p.join()

Теперь, когда dict1 и dict2 большие словари, это приводит к сбою кода с ошибкой

File "/anaconda3/lib/python3.6/multiprocessing/connection.py", line 393, in _send_bytes header = struct.pack("!i", n)
struct.error: 'i' format requires -2147483648 <= number <= 2147483647

, и я думаю, это потому, что pool делает копии dict1 и dict2 для каждой оценки моей функции.Вместо этого существует ли эффективный способ установить эти словари в качестве объектов общей памяти?map лучшая функция для этого?

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Если вы работаете в системе на основе fork (читай: не в Windows), одно из решений этой проблемы - поставить вопрос dict в глобальные переменные, написать функцию, которая не принимает их какаргументы, но просто получить доступ к ним из своих собственных глобальных, и использовать это.functools.partial, к сожалению, не подходит для этого варианта использования , но ваш вариант использования позволяет легко заменить его на глобальные и функцию def:

import multiprocessing

# Assumes wrange/dict1/dict2 defined or imported somewhere at global scope,
# prior to creating the Pool
def par_func(x):
    return f(x, wrange, dict1, dict2)

# Using with statement implicitly terminates the pool, saving close/join calls
# and guaranteeing an exception while mapping doesn't leave the pool alive indefinitely
with multiprocessing.Pool(4) as p:
    ssdat = p.map(par_func, wrange)

Изменения вdict1 / dict2 не будет отражаться между процессами после создания Pool, но вы все равно используете его только для чтения, так что это не проблема.

Есливы работаете в Windows или вам нужно изменить dict s, вы всегда можете создать multiprocessing.Manager и создать dict прокси с помощью dict метода менеджера (они являются общими dict s, обновлено о назначении клавиш), но это уродливее и медленнее, поэтому я бы не одобрил это, если это вообще возможно.

0 голосов
/ 04 марта 2019

Если вы хотите разделить память между процессами, использующими многопроцессорность, вам нужно явно обмениваться объектами с multiprocessing.Array .Это не идеально, так как вы хотите получить доступ к элементам из диктовок, и поиск правильных данных может занять много времени.Вероятно, есть способы обойти это, если это станет для вас проблемой.

Как упоминалось @Peque, другой вариант - использовать threading .При многопоточности память автоматически распределяется между всеми процессами, но вы можете столкнуться с проблемами производительности из-за глобальной блокировки интерпретатора (GIL).GIL - это способ Python защитить вас от потоков и избежать гонок.

...