2016-07-15 2 views
2

Вчера я задал вопрос: Reading data in parallel with multiprocessЗаполнение словаря параллельно с многопроцессорной

Я получил очень хорошие ответы, и я реализовал решение, указанное в ответ я помеченный как правильно.

def read_energies(motif): 
    os.chdir("blabla/working_directory") 
    complx_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    lig_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    return motif, complx_ener, lig_ener 

COMPLEX_ENERGIS = {} 
LIGAND_ENERGIES = {} 
p = multiprocessing.Pool(processes=CPU) 
for x in p.imap_unordered(read_energies, peptide_kd.keys()): 
    COMPLEX_ENERGIS[x[0]] = x[1] 
    LIGAND_ENERGIES[x[0]] = x[2] 

Однако это решение занимает столько же времени, как если бы я просто перебрать peptide_kd.keys() и заполнить DataFrames один за другим. Почему это так? Есть ли способ заполнить нужные дикты параллельно и фактически увеличить скорость? Я запускаю его на 48-жильном HPC.

+0

Возможно, накладные расходы на использование многопроцессорности больше, чем на выполнение сложной обработки функций. Возможно, когда 'read_energies()' обрабатывает числовые кадры с переменными номерами, каждый раз позволял бы вам настраивать вещи в точку, там было выгодно. – martineau

ответ

3

Вы несете достаточное количество накладных расходов в (1) запуске каждого процесса и (2) копируете pandas.DataFrame (и т. Д.) Для нескольких процессов. Если вам просто нужно иметь dict, который должен быть параллелен, я бы предложил использовать общую память dict. Если ни один ключ не будет перезаписан, это легко, и вам не придется беспокоиться о блокировках.

(Примечание Я использую multiprocess ниже, который является ответвлением multiprocessing - но только так я могу продемонстрировать от переводчика, в противном случае, вы должны были бы сделать ниже от __main__).

>>> from multiprocess import Process, Manager 
>>> 
>>> def f(d, x): 
... d[x] = x**2 
... 
>>> manager = Manager() 
>>> d = manager.dict() 
>>> job = [Process(target=f, args=(d, i)) for i in range(5)] 
>>> _ = [p.start() for p in job] 
>>> _ = [p.join() for p in job] 
>>> print d 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 

Это решение не делает копии dict разделить между процессами, так что часть накладных расходов снижается. Для больших объектов, таких как pandas.DataFrame, это может быть значительным по сравнению со стоимостью простой операции, такой как x**2. Аналогичным образом, нереста Process может занять некоторое время, и вы, возможно, сможете выполнить вышеизложенное даже быстрее (для легких объектов) с помощью потоков (т. Е. От multiprocess.dummy вместо multiprocess для вашего первоначально размещенного решения или моего выше).

Если вы сделать потребность поделиться DataFrames (как ваш код предполагает, а не как задает вопрос), вы могли бы быть в состоянии сделать это путем создания совместно используемой памяти numpy.ndarray.

+0

Спасибо за ответ! Я собираюсь попробовать это сейчас, но сначала я хотел бы что-то спросить. Я не понимаю разницы между упомянутыми «разделяемыми» фреймами данных (переменные, которые я думаю). Почему мой код подразумевает, что я использую общий DataFrame? Работа, которую я хочу сделать параллельно, так же, как вы описали, заполнить словарь и использовать его по-разному (читайте данные внутри него), но ничего не меняйте внутри него. –

+0

Причина, по которой я сказал, что вы можете изучить массивы разделяемой памяти, заключается в том, что вы возвращаете два экземпляра DataFrame из каждого «Процесса». Однако вам сложно указать, нужно ли вам это делать или нет, поскольку вы только представили метакод. –

+0

О, я вижу. Мне нужны оба «DataFrames». сложно ли возвратить два из них? Было бы проще сделать это двумя разными шагами? –

Смежные вопросы