#python-3.x #pandas #flask #multiprocessing
Вопрос:
Я довольно смущен тем, как лучше всего сделать то, что я пытаюсь сделать.
Чего я хочу?
- Вызов API для приложения flask
- Маршрут колбы запускает 4-5 многопроцессорных процессов с использованием модуля процесса и объединяет результаты(в разрезанном фрейме данных pandas) с помощью общих менеджеров().список()
- Верните вычисленные результаты обратно клиенту.
Моя реализация:
pos_iter_list = get_chunking_iter_list(len(position_records), 10000) manager = Manager() data_dict = manager.list() processes = [] for i in range(len(pos_iter_list) - 1): temp_list = data_dict[pos_iter_list[i]:pos_iter_list[i 1]] p = Process( target=transpose_dataset, args=(temp_list, name_space, align_namespace, measure_master_id, df_searchable, products, channels, all_cols, potential_col, adoption_col, final_segment, col_map, product_segments, data_dict) ) p.start() processes.append(p) for p in processes: p.join()
Моя структура каталогов:
- main.py(flask entry point) - helper.py(contains function where above code is executed amp; calls transpose_dataset function)
Ошибка, которую я получаю при выполнении того же самого? Ошибка времени выполнения: Для предоставленного модуля «mp_main«не найден корневой путь. Это может произойти из-за того, что модуль был получен из крючка импорта, который не предоставляет информацию об имени файла, или из-за того, что это пакет пространства имен. В этом случае корневой путь должен быть указан явно.
Не уверен, что здесь пошло не так, список менеджеров отлично работает, когда звонят из sample.py файл с использованием if __name__ == '__main__':
Обновление: Тот же фрагмент кода отлично работает на моем MacBook, а не на ОС Windows.
Вызов API образца колбы:
@app.route(PREFIX "ping", methods=['GET']) def ping(): man = mp.Manager() data = man.list() processes = [] for i in range(0,5): pr = mp.Process(target=test_func, args=(data, i)) pr.start() processes.append(pr) for pr in processes: pr.join() return json.dumps(list(data))
Комментарии:
1. Полная обратная связь была бы очень полезна. Это почти наверняка проблема компоновки / структуры кода, связанная с возможностью импорта при использовании «spawn» против «fork» (я предполагаю, что в вашем macos есть немного старая версия python, все еще по умолчанию использующая «fork»).
2. Вы упоминаете , что используете
if __name__ == "__main__":
, но вы должны убедиться, что в основном все, что выходит за рамки определений функций и классов, находится внутри этого. Похоже, что flask пытается запустить новый экземпляр сервера в дочернем процессе и терпит неудачу.3. вероятно, все сводится к
app = Flask(__name__)
тому, использовали ли вы шаблон из быстрого запуска docs.. Поместите это и все ваши@app.route
определения функций внутриif __name__ == "__main__":
блока, чтобы он не пытался создать другой сервер при импорте дочернего процесса. Возможно , можно было бы изменить наapp = Flask("__main__")
, но я не понимаю последствий этого.4. @Aaron, Это сработало для меня, однако немного непонятно, почему дочерний процесс пытается снова запустить приложение flask? То же самое не происходит для macOS.
Ответ №1:
У стека есть постоянная ошибка, мешающая мне комментировать, поэтому я просто напишу ответ..
В Python есть 2 (основных) способа запуска нового процесса: «порождение» и «вилка». Fork-это системная команда, доступная только в *nix (читай: linux или macos), и поэтому spawn-единственная опция в Windows. После 3.8 spawn будет использоваться по умолчанию в macOS, но форк все еще доступен. Большая разница в том, что fork в основном создает копию существующего процесса, в то время как spawn запускает совершенно новый процесс (например, просто открывает новое окно cmd). Есть много нюансов в том, почему и как, но для того, чтобы иметь возможность запускать функцию, которую вы хотите, чтобы дочерний процесс запускался с помощью spawn, дочерний файл должен быть в import
основном файле. Импорт файла равносильен простому выполнению этого файла, а затем, как правило, привязке его пространства имен к переменной: import flask
будет выполняться flask/__ini__.py файл и привязать его глобальное пространство имен к переменной flask
. Однако часто существует код, который используется только основным процессом и не нуждается в импорте / выполнении в дочернем процессе. В некоторых случаях повторный запуск этого кода фактически нарушает работу, поэтому вместо этого вам нужно предотвратить его запуск вне основного процесса. Это учитывается в том, что «волшебная» переменная __name__
равно только "__main__"
в основном файле (а не в дочерних процессах или при импорте модулей).
В вашем конкретном случае вы создаете новый app = Flask(__name__)
, который выполняет некоторую проверку и проверки перед запуском сервера. Это один из этапов настройки/проверки, который он выполняет при запуске из дочернего процесса. Исправить это, не позволяя ему работать вообще, — это более чистое решение imao, но вы также можете исправить его, придав ему значение, при котором он не будет отключаться, а затем просто никогда не запускайте этот дополнительный сервер (снова защитив его if __name__ == "__main__":
).