Менеджер многопроцессорной обработки Python показывает ошибку при использовании в API flask

#python-3.x #pandas #flask #multiprocessing

Вопрос:

Я довольно смущен тем, как лучше всего сделать то, что я пытаюсь сделать.

Чего я хочу?

  1. Вызов API для приложения flask
  2. Маршрут колбы запускает 4-5 многопроцессорных процессов с использованием модуля процесса и объединяет результаты(в разрезанном фрейме данных pandas) с помощью общих менеджеров().список()
  3. Верните вычисленные результаты обратно клиенту.

Моя реализация:

 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__": ).