2013-09-16 2 views
1

Привет StackOverflow пользователей,многопроцессорных функции с постоянными и Iterable аргументов

Я попытался посмотреть это вверх, но не смог найти ответ: Я в основном хотел бы обработать функцию параллельно (независимые процессы!) И функцию имеет один итеративный (x) и несколько постоянных аргументов (k, d). Вот очень упрощенный пример:

from multiprocessing import * 

def test_function(args): 
    k = args[0] 
    d = args[1] 
    x = args[2] 
    del args 

    return k*x + d 

if __name__ == '__main__': 
    pool = Pool(processes=2) 

    k = 3. 
    d = 5. 

    constants = [k,d] 
    xvalues = range(0,10) 
    result = [pool.apply_async(test_function, constants.append(i)) for i in xvalues] 

    output = [r.get() for r in result] 

    print output 
    #I expect [5.0, 8.0, 11.0, 14.0, 17.0, 20.0, 23.0, 26.0, 29.0, 32.0] 

Это дает мне следующее сообщение об ошибке:

Traceback (most recent call last): 
    File "test_function.py", line 23, in <module> 
    output = [r.get() for r in result] 
    File "C:\Program Files\Python2.7\lib\multiprocessing\pool.py", line 528, in get 
    raise self._value 
TypeError: test_function() argument after * must be a sequence, not NoneType 

Так что мои вопросы:

Что это сообщение об ошибке на самом деле означает?

Как исправить это, чтобы получить ожидаемые результаты (см. Последнюю строку примера кода)?

Есть ли лучший/рабочий/элегантный способ для линии, которая вызывает apply_sync?

FYI: Я новичок здесь и на python, пожалуйста, несите меня и дайте мне знать, если мой пост нуждается в подробностях.

Большое спасибо за любые предложения!

ответ

1

Что означает это сообщение об ошибке?

Значение, возвращаемое методом append всегда None, поэтому при выполнении:

pool.apply_async(test_function, constants.append(i)) 

вы звоните pool.apply_asynch с None как args аргумент, но apply_asynch ожидает Iterable в качестве аргумента. То, что делает apply_asynch, называется tuple-unpacking.

Как исправить это, чтобы получить ожидаемые результаты?

Для достижения ожидаемого результата простой конкатенации i констант:

pool.apply_asynch(test_function, (constants + [i],)) 

Есть ли лучше/рабочий/элегантный способ для линии, которая вызывает apply_sync?

Обратите внимание, что вы должны обернуть все аргументы в кортеж одного элемента, так как ваш test_function принимает единственный аргумент. Вы можете изменить его таким образом:

def test_function(k, d, x): 
    # etc 

И просто использовать:

pool.apply_asynch(test_function, constants + [i]) 

apply_asynch автоматически распаковывать args в трех аргументов функции с помощью tuple -unpacking. (внимательно прочитайте документацию для Pool.apply и друзей).


Есть ли лучше/рабочий/элегантный способ для линии, которая вызывает apply_sync?

Как отметили Сила вместо использования в список значений, которые вы должны использовать Pool.map или Pool.map_asynch методов, которые делают это для вас.

Например:

results = pool.map(test_function, [(constants + [i],) for i in xvalues]) 

Однако обратите внимание, что в этом случае test_function должен принимать один аргумент, поэтому вы должны вручную распаковывать константы и x, как вы делали в вашем вопросе.


Кроме того, как общее предложение:

  • В вашем test_function нет абсолютно никакой необходимости делать del args. Будет только замедлить выполнение функции (на очень небольшое количество). Используйте del экономно, только при необходимости.
  • Вместо назначения вручную элементы из кортежа вы можете использовать следующий синтаксис:

    k, d, x = args 
    

    что эквивалентно (возможно, немного медленнее):

    k = args[0] 
    d = args[1] 
    x = args[2] 
    
  • Ожидать большие медленного падения, используя multiprocessing для вызова таких простых функций. Стоимость связи и синхронизации процессов довольно велика, поэтому вы должны избегать вызова простой функции и, когда это возможно, пытаться работать «в кусках» (например, вместо отправки каждого запроса отдельно, отправьте список из 100 запросов работнику в один аргумент).
+2

В любом случае ему лучше будет обслуживать 'pool.map' или' pool.map_asynch'. –

+0

Спасибо за отличный ответ и Сайласу за дополнение! Я включил все предложения, но мне пришлось изменить строку pool.map следующим образом: 'result = pool.map (test_function, [константы + [i] для i в xvalues])' А также последующая строка с '.get () 'на самом деле лишний, печать' result' дает правильный ответ.Спасибо также за общие предложения. – ilun

0

constants.append (i) возвращает None, вы должны сначала добавить значения, а затем использовать constants в качестве второго параметра.

>>> constants = [] 
>>> i = 2 
>>> bug_value = constants.append(i) 
>>> constants 
[2] 
>>> bug_value is None 
True 
>>> 

Использование result = [pool.apply_async(test_function, constants+ [i]) for i in xvalues] действительно

список + список присоединяет два списка и возвращает полученный список.

+0

Спасибо за ваш краткий пример! Моя проблема заключалась в том, что я ожидал чего-то вроде конкатенации из 'constants.append. (I)'. – ilun

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