Ошибка именования глобальных переменных при многопроцессорной обработке только в подкаталоге

#python #python-2.7 #multiprocessing #nameerror

#python #python-2.7 #многопроцессорная обработка #ошибка имени

Вопрос:

У меня есть основной процесс, который использует execfile и запускает скрипт в дочернем процессе. Это работает нормально, если скрипт не находится в другом каталоге — тогда все ломается.

Это в mainprocess.py :

 from multiprocessing import Process

m = "subdir\test.py"

if __name__ == '__main__':
    p = Process(target = execfile, args = (m,))
    p.start()
  

Затем в подкаталоге, точно названном subdir, у меня есть test.py

 import time

def foo():
    print time.time()

foo()
  

При запуске mainprocess.py я получаю сообщение об ошибке:

 NameError: global name 'time' is not defined
  

но проблема не ограничивается именами модулей — иногда я получаю ошибку в имени функции в других фрагментах кода.

Я пытался импортировать time в mainprocess.py , а также внутри if инструкции там, но ни то, ни другое не дало никакого эффекта.

Один из способов избежать ошибки (я этого не пробовал) — скопировать test.py в родительский каталог и вставить строку в файл, чтобы os.chdir вернуться в исходный каталог. Однако это кажется довольно неаккуратным.

Итак, что происходит?

Комментарии:

1. Почему бы не использовать subprocess модуль для этого?

Ответ №1:

Решение состоит в том, чтобы изменить инициализацию вашего процесса:

 p = Process(target=execfile, args=(m, {}))
  

Честно говоря, я не совсем уверен, почему это работает. Я знаю, что это как-то связано с тем, в какой словарь (локальные или глобальные) добавляется импорт времени. Кажется, что когда ваш импорт выполняется в test.py это обрабатывается как локальная переменная, потому что работает следующее:

 import time        # no foo() anymore
print(time.time()) # the call to time.time() is in the same scope as the import
  

Однако также работает следующее:

 import time
def foo():
    global time
    print(time.time())
foo()
  

Этот второй пример показывает мне, что импорт по-прежнему присваивается какому-то виду глобального пространства имен, я просто не знаю, как и почему.

Если вы вызываете execfile() обычным способом, а не в подпроцессе, все выполняется нормально, и фактически, вы можете использовать модуль time в любом месте после вызова execfile() в вашем основном процессе, потому что время было перенесено в то же пространство имен. Я думаю, что, поскольку вы запускаете его в подпроцессе, нет пространства имен на уровне модуля, которому должен быть назначен импорт (execfile не создает объект модуля при вызове). Я думаю, что когда мы добавляем пустой словарь к вызову execfile, мы добавляем аргумент глобального словаря, таким образом предоставляя механизму импорта глобальное пространство имен для присвоения имени time.

Некоторые ссылки для фона:

1) Страница руководства по пространствам имен и области действия — сначала посмотрите здесь объяснения встроенных, глобальных и локальных пространств имен

2) Документы Python по команде execfile

3) Очень похожий вопрос на сайте, отличном от SO