龙卷风完成()召唤两次

时间:2015-04-10 10:37:53

标签: python asynchronous tornado coroutine

我用龙卷风和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 ...

3 个答案:

答案 0 :(得分:2)

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

你需要添加某种协调来确保get()协程在回调完成请求之前不会返回(toro.Event对此有利)或者摆脱{{1订阅时使用显式回调。在任何一种情况下,您应该只在yield gen.Task方法中使用@asynchronous@coroutine,而在其他方法中不允许装饰。

答案 1 :(得分:0)

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

正如@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 :(得分:0)

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