Остановить многопроцессорный сервер Python BaseManager 'serve_forever'?

У меня есть следующие настройки в Python 3.6 для межпроцессного взаимодействия:

from multiprocessing.managers import BaseManager
class MyManager(BaseManager): pass
MyManager.register('get_instance', callable=lambda:my_instance)
m = MyManager(address=('', 50000), authkey=b'key')
s = m.get_server()
s.serve_forever()

Чтобы не блокировать мой цикл сообщений более крупного приложения, я использовал поток, содержащий эту настройку. Так s.serve_forever() на самом деле работает внутри run функция потока.

Это сделано в соответствии с документацией. И сама установка отлично работала с менеджерами клиентов, звонящими в общий экземпляр.

Тем не менее, я не нашел способа остановить этот сервер serve_forever. Поскольку в документации не упоминалось об этом, я проверил исходный код. Есть stop_event который якобы я могу set выйти из цикла. Но это не сработало, так как accepter демон / поток все еще работает. И я не могу позвонить shutdown на объекте сервера, потому что у меня нет объекта сокета c,

Так как мне выключить этот сервер?

пс. С помощью BaseManager.start() на самом деле это не вариант для меня, потому что сервер в моем случае использует асинхронный цикл сообщений, доступ к которому возможен только в процессе запуска. BaseManager.start() порождает новый процесс, который больше не имеет доступа к циклу сообщений. get_server().serve_forever() с другой стороны, работает внутри вызывающего процесса.

3 ответа

Вот хак после прочтения multiprocessing.managersисточник, снятый с _finalize_manager(), в основном создавая соединение с сервером и отправляя сообщение о завершении работы

      from multiprocessing.managers import dispatch,listener_client

_Client = listener_client['pickle'][1]
# address and authkey same as when started the manager
conn = _Client(address=('127.0.0.1', 50000), authkey=b'key')
dispatch(conn, None, 'shutdown')
conn.close()

Попробуйте это на сервере:

import threading

s = m.get_server()
stop_timer = threading.Timer(1, lambda:s.stop_event.set())
MyManager.register('stop', callable=lambda:stop_timer.start())
s.serve_forever()

И в клиенте:

MyManager.register('stop')
m.stop()

ОБНОВИТЬ:

Я решил проблему тайм-аута, отложив stop_event.set() с threading.Timer

OLD:

Однако на разных компьютерах вы можете столкнуться с длительным временем ожидания, поскольку stop() Метод не может получить данные, этот ответ говорит об этом - но я не мог заставить его работать:

правильно отключить многопроцессорный удаленный менеджер

Я новичок в многопроцессорных менеджерах, я обновлю этот ответ, если найду лучшее решение. (ОБНОВЛЕНИЕ: найдено, обновлено)

Вы можете обернуть / использовать менеджер запуска / выключения, чтобы избежать этого вечно работающего сервера (start() запускает сервер для вас):

m = MyManager(address=('', 50000), authkey=b'key')
m.start()
# do something
m.shutdown()
Другие вопросы по тегам