Использование параллельного python для распараллеливания цикла по узлам в networkx

Я делаю сложный расчет в networkx. Расчет включает в себя расчет некоторого количества снова и снова для каждого узла в сети. В качестве примера такого расчета предположим, что мы хотим вычислить среднюю степень соседей каждого узла в сети и сохранить это значение как атрибут узла. Следующий фрагмент работает для меня:

import networkx as nx

G = nx.erdos_renyi_graph(10, 0.5)

def ave_nbr_deg(node):
    value = 0.
    for nbr in G.neighbors(node):
        value += G.degree(nbr)
    G.node[node]['ave_nbr_deg'] = value/len(G.neighbors(node))

for node in G.nodes():
    ave_nbr_deg(node)

print G.nodes(data = True)

Это дает мне:

[(0, {'ave_nbr_deg': 5.4}), (1, {'ave_nbr_deg': 5.0}), (2, {'ave_nbr_deg': 5.333333333333333}), (3, {'ave_nbr_deg': 5.2}), (4, {'ave_nbr_deg': 5.6}), (5, {'ave_nbr_deg': 5.6}), (6, {'ave_nbr_deg': 5.2}), (7, {'ave_nbr_deg': 5.25}), (8, {'ave_nbr_deg': 5.5}), (9, {'ave_nbr_deg': 5.5})]

Вот сам у меня есть небольшое сомнение. Объект G создается вне функции ave_nbr_deg, и я понятия не имею, откуда у функции информация, хотя я и не объявлял ее глобальной.

Теперь я хочу использовать параллельный модуль Python, чтобы использовать все ядра в моей системе для этого расчета. После внесения некоторых изменений в приведенный выше код я получаю следующий код:

import networkx as nx
import pp

G = nx.erdos_renyi_graph(10, 0.5)

def ave_nbr_deg(node):
    value = 0.
    for nbr in G.neighbors(node):
        value += G.degree(nbr)
    G.node[node]['ave_nbr_deg'] = value/len(G.neighbors(node))

job_server = pp.Server(ppservers = ())

print "Starting pp with", job_server.get_ncpus(), "workers"

for node in G.nodes():
    job_server.submit(ave_nbr_deg, args = (node,))()

print G.nodes(data = True)

Но он возвращает следующую ошибку:

An error has occured during the function execution
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/ppworker.py", line 90, in run
    __result = __f(*__args)
  File "<string>", line 5, in ave_nbr_deg
NameError: global name 'G' is not defined

Я пробовал всевозможные вещи, включая имя модуля nx в отправке и так далее. Однако я не понимаю, в чем именно проблема. К сожалению, документация по smp слишком короткий, чтобы решить эту проблему. Я был бы очень признателен, если бы кто-нибудь здесь мог помочь мне с этим.

заранее спасибо


person Peaceful    schedule 07.03.2016    source источник


Ответы (1)


Чтобы ответить на ваш первый вопрос: Python сначала ищет переменные в локальном пространстве имен. Если он их там не найдет, то он переместится в родительское пространство имен и будет искать его там. Вот как он находит G, хотя G не объявлен локально. Вот дополнительная информация об областях видимости переменных: rule/" rel="nofollow">Область действия Python

Вероятно, есть два решения:

1 - передать G в качестве аргумента функции ave_nbr_deg, например

for node in G.nodes():
    job_server.submit(ave_nbr_deg, args = (node,G))()

2 — объявить G как глобальную переменную в аргументах отправки (из документации Parallel Python)

   submit(self, func, args=(), depfuncs=(), modules=(), 
       callback=None, callbackargs=(), group='default', globals=None)
Submits function to the execution queue

func - function to be executed
args - tuple with arguments of the 'func'
depfuncs - tuple with functions which might be called from 'func'
modules - tuple with module names to import
callback - callback function which will be called with argument 
        list equal to callbackargs+(result,) 
        as soon as calculation is done
callbackargs - additional arguments for callback function
group - job group, is used when wait(group) is called to wait for
jobs in a given group to finish
globals - dictionary from which all modules, functions and classes
will be imported, for instance: globals=globals()

В этом случае вызов следующего должен работать:

for node in G.nodes():
    job_server.submit(ave_nbr_deg, args = (node,G), globals=globals())()
person user1337732    schedule 07.03.2016
comment
К сожалению, оба они не работают. В частности, они дают пустые словари для атрибутов узлов. Кроме того, на мой взгляд, передача всего G функции для каждого узла фактически ухудшит производительность. - person Peaceful; 07.03.2016