@igudo

Как остановить asyncio server.serve_forever() из другого потока?

Есть 2 потока. В одном отлавливаются сигналы (и еще много всего, но для вопроса это всё лишнее), а в другом - происходит server.serve_forever():

import sys
import signal
import asyncio
from threading import Thread

class Server:
    def run_serve(self):  # функция потока
        asyncio.run(self.serve())

    async def serve(self):  # функция запуска сервера, вызывается асинхронно в потоке
        self.server = await asyncio.start_server(self.handle_connection, '0.0.0.0', 5050)
        async with self.server:
            await self.server.serve_forever()

    async def handle_connection(self, reader, writer):  # просто эхо-заглушка принятия соединения
        while True:
            data = await reader.read(2048)
            writer.write(data)

    def close(self):  # должна закрыть self.server и завершить выполнение потока (функции run_serve)
        self.server.close()  # Работает только со второго раза, принудительным завершением

# Функция обработчика
def signal_handler(signal, frame):
    server.close()
    sys.exit(0)

# Обработчик
signal.signal(signal.SIGINT, signal_handler)

# Запускаем сервер
server = Server()
thread = Thread(target=server.run_serve)
thread.start()

while True:
    pass  # здесь что-то происходит


Как корректно завершить работу сервера и asyncio.run()? Можно ли так сделать вообще? Пробовал останавливать сам loop, получая его в том потоке. Не вышло. Помогите пожалуйста, хочу разобраться, может я вообще построил некорректно всё и нужно по другому? Но у меня запускается несколько экземпляров класса Server, т.е. несколько потоков, так что думаю тут по другому никак
  • Вопрос задан
  • 486 просмотров
Решения вопроса 1
sgjurano
@sgjurano
Разработчик
Существует только один правильный способ остановить поток снаружи — взвести какой-нибудь флажок, на который поток будет смотреть в своём основном цикле и остановится сам.

А зачем вам много потоков с asyncio? Они вообще-то плохо сочетаются, а профита приносят мало, ведь ожидание и так асинхронное, а вычислительные операции в основном держат GIL.

Если всё же надо, то почему бы не воспользоваться ThreadPoolExecutor?
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы