безопасно ли не использовать инструкцию «if __name__ == ‘__main__'» для многопроцессорной обработки в python под unix?

#python #multiprocessing #python-multiprocessing

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

Вопрос:

Я пытаюсь реализовать гибкий конвейер на python, который я разделил на несколько модулей. Каждый из этих модулей можно использовать как отдельный инструмент, но иногда им также может потребоваться импортировать функции друг из друга. Я поместил общие простые функции, которые часто используются несколькими из этих модулей, в модуль «разное», который при необходимости импортируется всеми другими модулями.

Теперь каждый из этих модулей может захотеть запускать некоторые функции параллельно, используя многопроцессорную обработку (обычно вызывая некоторые внешние инструменты). Итак, я создал общую функцию «run_parallel», которая принимает список функций и соответствующие аргументы в качестве аргументов, определяет приоритет каждой из них и соответственно распределяет доступные ядра по ним, а затем запускает эти функции параллельно, используя многопроцессорную обработку и starmap().

Теперь я думаю, что эту функцию можно было бы поместить в модуль «разное» и ее можно было бы просто импортировать, когда любой из других функций необходимо выполнять задания параллельно. Однако, если я буду следовать (по-видимому) общему правилу всегда использовать if __name__ == '__main__ оператор для этого, это означает, что я не могу импортировать эту функцию и повторно использовать ее в нескольких модулях. Я никогда полностью не понимал это требование, но, похоже, оно имеет какое-то отношение к Windows, в частности? Мой конвейер будет работать ТОЛЬКО под unix.

Означает ли это, что я ДОЛЖЕН реализовать этот метод «run_parallel» отдельно для каждого из моих модулей? Или я могу просто безопасно оставить его, если мой код предназначен только для работы в средах linux / unix?

РЕДАКТИРОВАТЬ: теперь я понимаю, что просто совершенно неправильно понял использование этого оператора в руководствах и примерах использования для многопроцессорной обработки. Я подумал, что по какой-то причине это требуется также в любой функции, которая использует что-то из многопроцессорной обработки (и всегда был смущен, почему это так). Но в этих примерах они также защищали только ту часть кода примера, которая вызывала бы эту функцию, предотвращая ее автоматический вызов при каждом импорте (не препятствуя тому, чтобы функция была импортирована вообще, как я думал).). Полное непонимание!

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

1. Можете ли вы уточнить свой вопрос? Мне было трудно понять вас, но, похоже, вы путаете понятия. Для начала: все, что находится под `if name == » main «, выполняется только при прямом вызове модуля, но не при его импорте.

2. «это означает, что я не могу импортировать эту функцию и повторно использовать ее в нескольких модулях». Нет, это совсем не то, что это значит. Это означает, что когда вы повторно используете его где -то, он должен вызываться в защищенном коде.

3. Вопрос для @jov14: вы бы что-нибудь потеряли, включив в if __name__ == '__main__': ... любом случае? Я думаю, что нет.

4. @Николас Мартинес @ Джастин Эсекьель: Это именно моя проблема. У меня есть функция, которая принимает другие функции и запускает их параллельно. Это функция, которую необходимо импортировать, потому что таким образом ее можно применять для множества разных функций из разных модулей. Однако он не может быть импортирован из-за if __name__ =='__main__': оператора (или, скорее: его МОЖНО импортировать, но тогда он не запускается). Это крайне неудобно, и мой вопрос заключается в том, является ли это ограничение строго необходимым? И почему?

5. @jov14 извините, всю if __name__ == '__main__': идиому иногда называют «охраняемой», потому что вы защищаетесь от выполнения кода в этом блоке при импорте модуля. Я не уверен, чего именно вы не понимаете, но у вас есть какой-то модуль foo , в котором функции используют многопроцессорную обработку. Затем вы импортируете этот модуль import foo bar.py , скажем, и там в защищенном коде, который вы запускаете foo.some_function()

Ответ №1:

Когда вы запускаете скрипт или импортируете модуль, python выполняет весь код, написанный на уровне модуля. В случае такой функции, как

 def foo():
    pass
 

«выполнение» означает только присвоение вновь скомпилированного объекта функции переменной с именем «foo». Эти вещи не должны быть защищены if __name__ == "__main__": блоком. Вам нужно беспокоиться только о коде, который выполняет действие, например, о коде, который вызывает foo() .

Вызывается скрипт верхнего уровня, вызываемый для запуска программы на python "__main__" . Импортируемые вами модули не вызываются "__main__" , и if __name__ == "__main__": блок бессмыслен. Важно, чтобы модули были безопасными для импорта. То есть всегда должно быть безопасно импортировать модуль, не делая ничего, кроме инициализации. Действия модуля всегда должны находиться внутри функций или классов, которые вызываются из других мест.

Сценарий верхнего уровня отличается, он должен фактически запускать программу. if __name__ == "__main__": используется для обеспечения безопасности импорта скриптов верхнего уровня. Это не имеет значения (по крайней мере, для многопроцессорной обработки) для разветвленных систем, таких как Unix. Но Windows необходимо создать новый процесс и импортировать скрипт верхнего уровня — и этот импорт должен быть безопасным, он не может повторно выполнить саму программу.

Хотя вам не нужна эта защита в Unix, модули всегда должны быть безопасными для импорта. И это хорошая дисциплина и для сценариев высшего уровня. Зачем ограничивать выполнение кода, когда в этом нет необходимости?

Достойный рецепт для сценариев таков

 def main()
    do all the things
    return 0

if __name__ == "__main__":
    retcode = main()
    exit(retcode)
 

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

1. большое спасибо за разъяснение. Я действительно понял эту функцию этого оператора. Но у меня также почему-то сложилось впечатление, что любая функция, использующая многопроцессорную обработку, также нуждается в этом утверждении, потому что большинство примеров использования многопроцессорной обработки подчеркивали это утверждение так заметно. Теперь я вижу, что я, вероятно, неправильно истолковал это.

2. Правильно, функции в этом не нуждаются, как и импортированные модули. Только сценарий верхнего уровня, который выполняет программу и вызывает функцию.