Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 30, 2013 09:38:06

alekseyxxxx
От:
Зарегистрирован: 2011-11-22
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

Здравствуйте. Делаю приложение на торнадо. Написал тестовый обработчик

class AdminHandler(BaseHandler):
    @tornado.web.authenticated
    @tornado.web.asynchronous
    @gen.engine
    def get(self):
        response = yield gen.Task(self.acync_func_test, 'my')
        print response
        self.render('admin/index.html')
    def acync_func_test(self, argument, callback):
        for i in xrange(1,59999000):
            i**2+2-12
        callback(argument)
Функция выполняется, но при этом блокирует все для остальных клиентов. Т.е. новые клиенты ждут, пока обработается запрос для предыдущего. Как вызвать функцию асинхронно?



Отредактировано alekseyxxxx (Авг. 30, 2013 09:38:21)

Офлайн

#2 Авг. 30, 2013 10:52:02

lorien
От:
Зарегистрирован: 2006-08-20
Сообщения: 755
Репутация: +  37  -
Профиль  

Tornado gen.engine и простая функция

Я не знаю устройства торнады, могу лишь сказать, что если у вас в асинхронной системе выполняется какой-то код и в нём нету никаких точек прерывания, типа того же yield, то этот код будет выполняться без прерываний, весь. Никаких чудес не будет, если функция async_func_test что-то делает долго, то в этом время все будут ждать её. Видимо, в функции надо генерить с помощью yield точки прерывания, наверное так и сделано в торнаде, я не знаю, как ещё по другому можно реализовать такой фунционал в python

Офлайн

#3 Сен. 1, 2013 01:29:11

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

alekseyxxxx
Как вызвать функцию асинхронно?
Она и вызывается асинхронно, суть в том что она блокирующая, вам нужно использовать неблокирующие ф-ии.
Либо запустить ф-ию в другом потоке, но это плохой путь.
Лучше тяжелые обработки запускать в отдельном процессе.

Офлайн

#4 Сен. 1, 2013 08:50:43

alekseyxxxx
От:
Зарегистрирован: 2011-11-22
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

Ну вроде стало понятно.

o7412369815963
Либо запустить ф-ию в другом потоке, но это плохой путь.
Над этим тоже думал. На хабре есть пример, когда на каждый запрос создаются потоки. http://habrahabr.ru/post/116892/
class ThreadableMixin:
    def start_worker(self):
        threading.Thread(target=self.worker).start()
    def worker(self):
        try:
            self._worker()
        except tornado.web.HTTPError, e:
            self.set_status(e.status_code)
        except:
            logging.error("_worker problem", exc_info=True)
            self.set_status(500)
        tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.results))
    def results(self):
        if self.get_status()!=200:
            self.send_error(self.get_status())
            return
        if hasattr(self, 'res'):
            self.finish(self.res)
            return
        if hasattr(self, 'redir'):
            self.redirect(self.redir)
            return
        self.send_error(500)
А потом в обработчике запускают поток.
class Handler(tornado.web.RequestHandler, ThreadableMixin):
    def _worker(self):
        self.res = self.render_string("template.html",
            title = _("Title"),
			data = self.application.db.query("select ... where object_id=%s", self.object_id)
        )
    @tornado.web.asynchronous
    def get(self, object_id):
	self.object_id = object_id
        self.start_worker(
Это хороший путь? Просто GIL же все равно выполняет только один поток. Получается, что хоть клиенты и не блокируются, но ждут ответа дольше. Или я не так понимаю?)



Отредактировано alekseyxxxx (Сен. 1, 2013 08:51:55)

Офлайн

#5 Сен. 1, 2013 11:51:33

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

alekseyxxxx
Получается, что хоть клиенты и не блокируются, но ждут ответа дольше. Или я не так понимаю?)
Из за GIL питон код будет работать только в одном потоке, т.е. если вы блокируете питон-кодом for in xrange то другие потоки не работают, если вы заблокируете не питон-кодом (io операции, обычно ими блокируют, db.query, urllib.urlopen, time.sleep …) то другой питон-код в других потоках будет работать.

Т.е. делать потоки имеет смысл для работы с блокирующим io. Но все же разработчики торнадо говорят про потоки как крайнюю меру (сходу ссылку не нашел, возможно где то у них на трекере).
Плюс при введении потоков общая производительность приложения падает.

Для не больших проектов (нагрузок) нормально. Для больших, я бы вынес подобный функционал в отдельный процесс, и если необходимо, общался с ним через zmq, xmlrpc и т.п. Кстати из торнадо можно асинхронно вызывать процессы, пример

А вообще, возможно вам не нужен асинхронный фреймворк для всего. Например недавний проект я сделал на bottle (wsgi) + авторизация на tornado + чат и обмен командами через websocket на gevent. - по принципу “инструмент от задачи”, а вместо tornado для авторизации рассматривал node.js ;)

Вот ещё посмотрите эту тему, я там поплакался на большой проект под tornado.

Офлайн

#6 Сен. 1, 2013 13:05:45

alekseyxxxx
От:
Зарегистрирован: 2011-11-22
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

Просто в разработке есть приложение на tornado на websocket. Все общение идет только через вебсокеты. И интересно сколько способен выдержать tornado. Как я понял, если не писать ‘асинхронным стилем’, то клиенты будут блокироваться. Ну, например, самая простая функция:

def on_message(self, msg):
    user_id = msg['id']
    user = db.query(User).get(id)
И получается, что к примеру 2000 клиентов одновременно отправят запрос, то обработка будет последовательная. Ну тут запрос небольшой, но на более сложных будет ощутимая задержка. Т.е. преимущество торнадо тут никак не реализуется. Поэтому надо использовать асинхронные функции(ну типа pymongo для работы с бд). Я правильно понял?)

P.S. Видно у вас есть опыт разработки нагруженных приложений на tornado. Не подскажите, может есть полезные ссылки и ресурсы на которых можно поподробнее почитать. Гугл весь прошарил)



Отредактировано alekseyxxxx (Сен. 1, 2013 13:09:43)

Офлайн

#7 Сен. 1, 2013 15:19:29

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

alekseyxxxx
И получается, что к примеру 2000 клиентов одновременно отправят запрос, то обработка будет последовательная.
Да, для mongodb можете попробовать asyncmongo, не поддерживает весь функционал, но для 99% случаев достаточно. Он асинхронный - не будет блокировать.
alekseyxxxx
И интересно сколько способен выдержать tornado
Если процесс торнадо не будет справляться, то можно запустить их несколько экземпляров (форкнуть), и балансировщиком раскидать нагрузку (пример конфига nginx), таким же образом можно задействовать несколько серверов с кучей процессов торнадо, если нагрузка большая.

При балансировке клиенты могут быть подключены к разным процессам торнадо, и если клиенты между собой должны “общаться”, нужно думать как пересылать сообщения между процессами.

Офлайн

#8 Сен. 1, 2013 15:23:19

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

alekseyxxxx
Не подскажите, может есть полезные ссылки и ресурсы на которых можно поподробнее почитать.
Не знаю, я бы сначала сформулировал задачу, предполагаемые нагрузки, придумал бы несколько вариантов архитектуры, выложил на форуме для обсасывания, потом сделал бы прототип, потом если было б время, сделал бы нагрузочное тестирование.
Как то так…

Офлайн

#9 Сен. 1, 2013 15:55:41

alekseyxxxx
От:
Зарегистрирован: 2011-11-22
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

Ну сейчас на данный момент так и сделано. Т.е. нжинкс балансирует нагрузку на несколько инстансов торнадо. А клиенты с разных инстансов общаются через редис. Вариант с монго привел для примера) Основная база postgres, ну для него тоже есть асинхроная библиотека. Попробую реализовать через нее, и провести нагрузочное тестирование) Спасибо за пояснения)



Офлайн

#10 Сен. 2, 2013 14:59:08

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Tornado gen.engine и простая функция

Не подскажете на эту же тему каким образом лучше реализовать такое. Пользователь заходит на сайт, нажимает кнопочку, запускается действие(настройка свитча по snmp, например), длится оно около минуты и лог этого действия realtime отображается у пользователя. Начал делать через торнадо и вебсокеты, но наткнулся на тоже самое - два пользователя одновременно не могут запустить эту настройку. Как мне сейчас лучше поступить?



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version