Где объединить потоки, созданные в асинхронном обработчике торнадо? - PullRequest
10 голосов
/ 19 мая 2011

Это меня немного озадачило. Совершенно новый для торнадо и потоков в Python, так что я могу быть совершенно не в курсе того, что я пытаюсь сделать здесь.

Вероятно, лучше начать с упрощенного кода:

class Handler(tornado.web.RequestHandler):

  def perform(self):
     #do something cuz hey, we're in a thread!

  def initialize(self):
    self.thread = None

  @tornado.web.asynchronous
  def post(self):

    self.thread = threading.Thread(target=self.perform)
    self.thread.start()

    self.write('In the request')
    self.finish()

  def on_connection_close(self):
    logging.info('In on_connection_close()')
    if self.thread:
      logging.info('Joining thread: %s' % (self.thread.name))
      self.thread.join()

Моя проблема в том, что on_connection_close никогда не вызывается, запросы обрабатываются просто отлично. Во-вторых, я делаю что-то ужасное, вводя потоки таким образом?

Ответы [ 2 ]

12 голосов
/ 26 мая 2011

Я полагаю, Thread.join() будет блокироваться до тех пор, пока поток не закончится, вероятно, вы хотите этого избежатьВместо присоединения вы можете использовать обратный вызов потока для обработчика.

При использовании потоков помните, что tornado не является потокобезопасным, поэтому вы не можете использовать какие-либо методы RequestHandler (например) из потоков.

Это работает для меня:

import functools
import time
import threading
import logging

import tornado.web
import tornado.websocket
import tornado.locale
import tornado.ioloop

class Handler(tornado.web.RequestHandler):
    def perform(self, callback):
        #do something cuz hey, we're in a thread!
        time.sleep(5)
        output = 'foo'
        tornado.ioloop.IOLoop.instance().add_callback(functools.partial(callback, output))

    def initialize(self):
        self.thread = None

    @tornado.web.asynchronous
    def get(self):
        self.thread = threading.Thread(target=self.perform, args=(self.on_callback,))
        self.thread.start()

        self.write('In the request')
        self.flush()

    def on_callback(self, output):
        logging.info('In on_callback()')
        self.write("Thread output: %s" % output)
        self.finish()

application = tornado.web.Application([
    (r"/", Handler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Вы можете проверить это с помощью curl --no-buffer localhost:8888.Некоторые браузеры (Safari), кажется, ждут, пока соединение закроется, прежде чем отображать какие-либо выходные данные, что на некоторое время отбросило меня.

1 голос
/ 21 мая 2011

AFAIK, on_connection_close вызывается только тогда, когда клиент прерывает соединение, что может объяснить вашу проблему. Что касается потоков, я не знаю, что вы хотите сделать, но я не понимаю, почему вы захотите создать поток в запросе Tornado, поскольку одним из преимуществ Tornado является то, что вам не нужно использовать потоки. , Если бы я добавил join к вашему примеру, я бы поставил его перед self.finish(), однако, вы, вероятно, можете просто его опустить ... это будет зависеть от того, что вы хотите сделать с потоком, но помните, что Торнадо является однопоточным, и весь процесс будет заблокирован, если поток не завершится к моменту join().

...