【问题标题】:tornado finish() called twicetornado finish() 调用了两次
【发布时间】:2015-06-16 01:07:54
【问题描述】:

我用 tornado 和 tornadoredis 编写了一个彗星演示,演示可以工作,但有时会发生错误,我不知道如何修复它。任何人都可以帮助我吗?

错误:

[E 150410 18:18:44 web:1421] Uncaught exception GET /comet?channelKey=channel%3Awx4g1nej7fuu&message_id=193 (127.0.0.1)
    HTTPServerRequest(protocol='http', host='tornado.test.com', method='GET', uri='/comet?channelKey=channel%3Awx4g1nej7fuu&message_id=193', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Remote-Addr': 'xxx', 'Service': 'android', 'X-Forwarded-For': 'xxx', 'User-Agent': 'Apache-HttpClient/UNAVAILABLE (java 1.4)', 'Host': 'tornado.test.wolonge.com', 'X-Requested-With': 'XMLHttpRequest', 'X-Real-Ip': 'xxx', 'Cookie': 'logintoken=gsvimqqefr8f9duu66emjrbbe5_8be6AsNqW%2B3kwH7OsnT0OAKbZNNqnzabDIVcFDE8TvyozQ7h'})
    Traceback (most recent call last):
      File "/usr/lib64/python2.6/site-packages/tornado/web.py", line 1302, in _stack_context_handle_exception
        raise_exc_info((type, value, traceback))
      File "/usr/lib64/python2.6/site-packages/tornado/web.py", line 1489, in wrapper
        result = method(self, *args, **kwargs)
      File "/home/wwwroot/wolongge_mobile/app/tornado_push/models/ws_handle.py", line 53, in ready_finish
        self.finish(res)
      File "/usr/lib64/python2.6/site-packages/tornado/web.py", line 863, in finish
        raise RuntimeError("finish() called twice.  May be caused "
    RuntimeError: finish() called twice.  May be caused by using async operations without the @asynchronous decorator

我的代码在这里:

class GroupChat(tornado.web.RequestHandler):
    def initialize(self):
        print 'GroupChat here'
        self.c = tornadoredis.Client(host=CONFIG['REDIS_HOST'], port=CONFIG['REDIS_PORT'], password=CONFIG['REDIS_AUTH'])
    @tornado.gen.coroutine
    @tornado.web.asynchronous
    def get(self):
        try:
            self.key = self.get_argument('channelKey')
            # print 'key:%s' % self.key
            self.key = url_unescape(self.key);
            # print 'key:%s' % self.key
            if(self.key):
                yield tornado.gen.Task(self.c.subscribe, self.key)
                self.c.listen(self.on_message)
        except Exception, e:
            self.c.disconnect()
            self.ready_finish('Bad Request (Missing argument)')
            print e
        pass


    @tornado.web.asynchronous
    def on_message(self, msg):
        if (msg.kind == 'message'):
            print msg
            message_id = int(self.get_argument('message_id'))
            max_message_id = int(msg.body)
            if(message_id < max_message_id):
                self.ready_finish('1')
            else:
                self.ready_finish('0')
        elif (msg.kind == 'unsubscribe'):
            self.c.disconnect()

    @tornado.web.asynchronous
    def ready_finish(self, res):
        if (self.c.subscribed):
            self.c.unsubscribe(self.key)
        self.finish(res)


    def on_connection_close(self):
        print 'on_connection_close here'

另一个问题,@tornado.web.asynchronous 是正确的使用方式吗?每个方法都有@tornado.web.asynchronous ...

【问题讨论】:

    标签: python asynchronous tornado coroutine


    【解决方案1】:

    您需要 @tornado.web.asynchronous 仅用于 get 方法。同时删除get方法下的@tornado.gen.coroutine

    @tornado.web.asynchronous 的文档中所述 http://tornado.readthedocs.org/en/latest/web.html#tornado.web.asynchronous

    这个装饰器应该只应用于 HTTP 动词方法;它的 对于任何其他方法,行为都是未定义的。这个装饰器不 使方法异步;它告诉框架该方法是 异步。

    所以你不能将它用于on_messageready_finish,删除它。 对于on_messageready_finish,如果您有任何异步调用,您可以使用@tornado.gen.coroutine

    【讨论】:

      【解决方案2】:

      一般来说,避免混合使用协程和异步回调样式。在这里,你的 get() 方法是一个协程,它会在返回时自动完成请求,但它也启动了基于回调的listen(),它将在稍后尝试完成请求。

      您需要添加某种协调以确保 get() 协程在回调完成请求之前不会返回(toro.Event 对此有好处)或摆脱 yield gen.Task 并使用订阅时的显式回调。在任何一种情况下,您都应该在 get() 方法上只使用 @asynchronous@coroutine 之一,而在其他方法上不要使用装饰器。

      【讨论】:

        【解决方案3】:

        这个装饰器应该只应用于 HTTP 动词方法;对于任何其他方法,它的行为都是未定义的。这个装饰器不会使方法异步;它告诉框架该方法是异步的。为了使这个装饰器有用,该方法必须(至少有时)做一些异步的事情。

        【讨论】:

          猜你喜欢
          • 2013-11-11
          • 2017-06-25
          • 2013-01-21
          • 2012-09-08
          • 2016-04-27
          • 2019-02-27
          • 1970-01-01
          • 2019-12-04
          • 2018-09-15
          相关资源
          最近更新 更多