Остановить многопроцессорный сервер 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()