Я пишу пакет Python, который считывает список модулей (вместе со вспомогательными данными) из файла конфигурации.
Затем я хочу перебрать каждый из динамически загружаемых модулей и вызвать в нем функцию do_work (), которая порождает новый процесс, чтобы код выполнялся АСИНХРОННО в отдельном процессе.
На данный момент я импортирую список всех известных модулей в начале моего основного скрипта - это неприятный хакер, который я считаю, и он не очень гибкий, а также затрудняет обслуживание.
Это функция, запускающая процессы. Я хотел бы изменить его, чтобы динамически загружать модуль при его обнаружении. Ключ в словаре - это имя модуля, содержащего код:
def do_work(work_info):
for (worker, dataset) in work_info.items():
#import the module defined by variable worker here...
# [Edit] NOT using threads anymore, want to spawn processes asynchronously here...
#t = threading.Thread(target=worker.do_work, args=[dataset])
# I'll NOT dameonize since spawned children need to clean up on shutdown
# Since the threads will be holding resources
#t.daemon = True
#t.start()
Вопрос 1
Когда я вызываю функцию в своем скрипте (как написано выше), я получаю следующую ошибку:
AttributeError: объект 'str' не имеет атрибута 'do_work'
Это имеет смысл, поскольку ключ словаря представляет собой строку (имя импортируемого модуля).
Когда я добавляю заявление:
работник импорта
Перед созданием потока я получаю сообщение об ошибке:
ImportError: нет модуля с именем worker
Это странно, поскольку используется имя переменной, а не значение, которое она содержит - когда я печатаю переменную, я получаю значение (как я ожидал), что происходит?
Вопрос 2
Как я уже упоминал в разделе комментариев, я понимаю, что функция do_work (), написанная в порожденных дочерних элементах, должна очищаться после себя. Я понимаю, что нужно написать функцию clean_up, которая вызывается, когда do_work () успешно завершилась или было обнаружено необработанное исключение - есть ли что-нибудь еще, что мне нужно сделать, чтобы гарантировать, что ресурсы не просачиваются или не оставляют ОС в нестабильном состоянии?
Вопрос 3
Если я закомментирую оператор флага t.daemon, будет ли код работать АСИНХРОННО ?. Работа, выполняемая порожденными детьми, довольно интенсивна, и я не хочу ждать, пока один ребенок закончит, прежде чем порождать другого ребенка. Кстати, я знаю, что потоки в Python на самом деле являются своего рода разделением времени / нарезкой - это нормально
Наконец, есть ли лучший (более питонический) способ делать то, что я пытаюсь сделать?
[Изменить]
Прочитав немного больше о Pythons GIL и потоковой передаче (кхм - хак) в Python, я считаю, что лучше использовать вместо этого отдельные процессы (по крайней мере, IIUC, сценарий может использовать преимущества нескольких процессов, если они доступны), поэтому я порождать новые процессы вместо потоков.
У меня есть пример кода для создания процессов, но он немного тривиален (с использованием лямбад-функций). Я хотел бы знать, как его расширить, чтобы он мог иметь дело с запущенными функциями в загруженном модуле (как я делаю выше).
Это отрывок из того, что у меня есть:
def do_mp_bench():
q = mp.Queue() # Not only thread safe, but "process safe"
p1 = mp.Process(target=lambda: q.put(sum(range(10000000))))
p2 = mp.Process(target=lambda: q.put(sum(range(10000000))))
p1.start()
p2.start()
r1 = q.get()
r2 = q.get()
return r1 + r2
Как я могу изменить это, чтобы обработать словарь модулей и запустить функцию do_work () в каждом загруженном модуле в новом процессе?
2 ответа
Это было изменено для использования документации import () здесь: import и переработан для использования запрошенного модуля многопроцессорности, как описано здесь: multiprocessing. Это не было проверено.
def do_work(work_info):
q = mp.Queue()
for (worker, dataset) in work_info.items():
xworker = __import__(worker)
p = mp.Process(target=xworker.do_work, args=dataset).start()
q.put(p)
while not q.empty():
r = q.get()
Вопрос 1: используйте __import__()
.
Вопрос 2: почему бы просто не выполнить очистку в конце функции do_work()
?
Вопрос 3: поток демона IIRC просто означает, что программа не будет автоматически ждать завершения этого потока.
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.