MrBoriska
@MrBoriska
Пэхэпист самоучка, Питоност по Лутцу. C++

Как запустить в отдельном потоке вечный цикл по перебору какойто переменной в Tornado?

Задача такая. Нужно реализовать функцию, которая будет перебирать какой-то общедоступный список и уничтожать сама себя(вместе с потоком), в случае, если этот список вдруг стал пустым. Потом, при добавлении нового элемента в этот список, нужно как-то вызывать эту функцию, делающую тоже самое.
Функцию, я называю чистильщиком
Пример куска кода того, как делал я:
(импортирование модулей и прочие подробности я опустил, чтобы показать только суть)

# Обработчик WebSocket соединений
class WSHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        pass
    def on_close(self):
        # Узнаем остановлен ли чистильщик
        startCleaner = False
        if len(app.SessionsRestore) < 1:
            startCleaner = True
        
        # Временно сохраняем сессию в хранилище
        app.SessionsRestore.append({
            "sid":self.sid,
            "time_of_dead":datetime.now() + timedelta(minutes=5),
            })
        
        # Запускаем чистильщик сессий, если он был остановлен
        if startCleaner:
            app.clear_sessions_restore()
    
    def on_message(self,data):
        #Тут делаем разнообразные операции, не зависимо от чистильщика и т.п.
        pass

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/ws", WSHandler),
        ]
        # Это список, который должен перебирать чистильщик
        self.SessionsRestore = list()
        
        tornado.web.Application.__init__(self, handlers)

    # Чистильщик, работающий асинхронно
    # Следит за тем, чтобы сессии не лежали в этом хранилище слишком долго
    @tornado.web.asynchronous
    def clear_sessions_restore(self):
        while True:
            # Останавливаем чистильщик, если чистить нечего
            if len(self.SessionsRestore) < 1:
                break
            # Уменьшаем количество проходов в секунду
            time.sleep(5)
            # Осуществляем проход по хранилищу сессий
            for session in self.SessionsRestore:
                if session['time_of_dead'] > datetime.now():
                    self.SessionsRestore.remove(session)

# И примерно такой запуск серва
if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = Application()
    app.listen(8888)
    tornado.ioloop.IOLoop.instance().start()


Так вот, думал что использование декоратора @tornado.web.asynchronous сделает метод асинхронным, но не тут то было. На строчке, где вызывается этот метод, выполнение кода виснет до тех пор, пока не закончится "вечный" цикл внутри этого метода. В связи с этим не вижу ничего, кроме как писать все "ручками", используя модуль threading и т.п. Сделать это не составит труда, но хотелось бы сделать это ресурсами tornado . И не прибегать к велосипедам.

Веду разработку из Windows. Может из-за этого все проблемы и на *nix все будет окей? Если так, то подскажите, как можно реализовать пусть непроизводительную, но без ковыряния кода самого проекта нормальную поддержку асинхронности.
  • Вопрос задан
  • 3739 просмотров
Решения вопроса 2
mututunus
@mututunus
Backend developer (Python, Golang)
Торнадо тут не поможет. Надо выделить функцию в отдельный процесс.
Ответ написан
@sakuradaj
В Tornado работает главный цикл, можете попробовать добавить туда каллбек для периодического вызова вашего кода, главное что бы ваш код был неблокирующий.

Смотрите:

tornado.readthedocs.org/en/latest/ioloop.html
stackoverflow.com/questions/14260953/tornado-scheduler

ioloop.IOLoop.instance().add_timeout(time.time() + 5, callback)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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