Extending tornado.gen.Task

蓝咒 提交于 2019-12-11 00:08:55

问题


Here's the interesting bits of a stupid websocket clock:

class StupidClock(websocket.WebSocketHandler):
    clients = {}

    @web.asynchronous
    @gen.coroutine
    def open(self):
        self.is_open = True
        def enqueue(callback=None):
            self.__class__.clients[self] = callback
        while self.is_open:
            # This is the most interesting part!
            msg = yield gen.Task(enqueue)
            self.write_message(msg)

    def on_close(self):
        self.is_open = False
        del self.__class__.clients[self]

    @classmethod
    def periodic_update(cls):
        msg = time.time()
        # copy and clear before iterating to avoid infinite growth!
        clients = cls.clients.copy()
        cls.clients.clear()

        for obj, callback in clients.items():
            if obj.is_open:
                callback(msg)

# all the routing and application setup omitted...

loop = ioloop.IOLoop.instance()
cb = ioloop.PeriodicCallback(StupidClock.periodic_callback, 1,
                             io_loop=loop)
cb.start()
loop.start()

So my question is about deconstructing this statement:

msg = yield gen.Task(enqueue)

From the documentation, it's the same as:

result = yield gen.Task(func, args)
# is the same as
func(args, callback=(yield gen.Callback(key)))
result = yield gen.Wait(key)

It's quite clear to me what's happening with the first form (only one yield expression), but why must I yield control to Tornado to create a gen.Callback object?

How can one single yield expression be equivalent to two yield expressions? Mustn't control yield to Tornado two times? Yet, in the gen.Task form, I only yield control once!


回答1:


When you call yield gen.Callback it briefly transfers control to Tornado, but Tornado immediately returns to your code. It's just a way to communicate with the coroutine scheduler without using global (or thread-local) variables. It uses this weird pattern so it can work with libraries that predated the gen module and don't know anything about coroutines. For newer code (since Tornado 3.0), the recommended pattern has been for asynchronous functions to return a Future (which happens automatically if you use @gen.coroutine), which lets them be used in coroutines without gen.Task or gen.Callback.



来源:https://stackoverflow.com/questions/16655362/extending-tornado-gen-task

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!