Перезагрузка модуля Python для каждого процесса в модуле многопроцессорности

Есть ли способ загрузить копии процессов каждого процесса в процессах, созданных с использованием модуля многопроцессорности Python? Я пробовал это:

def my_fn(process_args):
    import my_module
    my_func()

... но суб-импорт в my_module загружается и кэшируется раз и навсегда. В частности, один из подимпов считывает файл конфигурации, значения которого устанавливаются на основе среды первого процесса. Если я попробую это:

def my_fn(process_args):
    try:
        my_module = reload(my_module)
    except NameError:
        import my_module

... суб-импорт my_module не перезагружается.

Ответ 1

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

class MyClass:
    module = import_module('amodule')

но вполне может быть достаточно хорош для ваших целей.

mymod.py

# Example submodule to re-import
print('import module mymod')

# demonstrate we can even import test as a module and it works
import sys
from test import deep_reload_module

value = 2

def a_function():
    pass

class XYZ:
    pass

class NewClass(object):
    pass

test.py

import importlib
import sys
import mymod


def deep_reload_module(name):

    mod = sys.modules.get(name)
    if not mod:
        importlib.import_module(name)
        return

    def get_mods_to_reload_recursively(name, modules_to_reload=None):
        modules_to_reload = modules_to_reload or set()
        mod = sys.modules[name]
        modules_to_reload.add(name)

        # loop through the attributes in this module and remember any
        # submodules we should also reload
        for attr in dir(mod):
            prop = getattr(mod, attr)
            if isinstance(prop, type(mymod)):
                modname = attr
            elif hasattr(prop, '__module__'):
                modname = prop.__module__
                if not modname:
                    continue
            else:
                # this thing is not a module nor does it come from another
                # module, so nothing to reimport.
                continue

            if modname in sys.builtin_module_names:
                # probably best not to reimport built-ins...
                continue

            if modname in modules_to_reload:
                # this is already marked for reimporting, so avoid infinite
                # recursion
                continue

            # get_mods_to_reload... will update modules_to_reload so no need to
            # catch the return value
            get_mods_to_reload_recursively(modname, modules_to_reload)

        return modules_to_reload

    mods_to_reload = get_mods_to_reload_recursively(name)
    for mtr in mods_to_reload:
        # best to delete everything before reloading so that you are
        # sure things get re-hooked up properly to the new modules.
        print('del sys.modules[%s]' % (mtr,))
        del sys.modules[mtr]

    importlib.import_module(name)


if __name__ == '__main__':
    orig_mymod_id = id(sys.modules['mymod'])
    deep_reload_module('mymod')
    assert orig_mymod_id != id(sys.modules['mymod'])

Затем вам просто нужно вызвать deep_reload_module('module') всякий раз, когда начинается новый процесс или даже проще в начале каждого задания многопроцессорности.

NB: это сильно зависит от кода, который живет за пределами модуля, который вы хотите использовать reimport, который ранее не импортировал ничего из этого модуля, потому что если он будет тогда, этот код будет продолжать использовать старый модуль или разрыв.

например. если у вас есть код, который делает это:

from module_to_reimport import a_function

Но явным образом не сохранял module_to_reimport где-либо явно, тогда a_function может потерпеть неудачу, когда он вызывается после того, как модуль повторно импортируется, поскольку он поддерживает только слабую ссылку на globals(), определенную в module_to_reimport, и это будет все уничтожаются, удаляя модуль из sys.modules.

Ответ 2

Поместите функцию в my_module, например:

def my_realod():
try:
    my_sub_module = reload(my_sub_module)
except NameError:
    import my_sub_module  

Вызвать my_reload следующим образом:

def my_fn(process_args):
try:
    my_module = reload(my_module)
    my_module.my_reload()

except NameError:
    import my_module