2

这是一个愚蠢的 websocket 时钟的有趣之处:

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()

所以我的问题是关于解构这个陈述:

msg = yield gen.Task(enqueue)

从文档中,它与以下内容相同:

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

我很清楚第一种形式(只有一个yield表达式)发生了什么,但为什么我必须将控制权交给 Tornado 来创建一个gen.Callback对象?

一个yield表达式如何等同于两个yield表达式?不是必须控制两次对 Tornado 的让步吗?然而,在gen.Task表格中,我只让步一次!

4

1 回答 1

0

当您调用yield gen.Callback它时,它会短暂地将控制权转移给 Tornado,但 Tornado 会立即返回给您的代码。这只是一种无需使用全局(或线程局部)变量即可与协程调度程序进行通信的方式。它使用这种奇怪的模式,因此它可以与gen模块之前的库一起使用,并且对协程一无所知。对于较新的代码(自 Tornado 3.0 起),推荐的模式是让异步函数返回 a Future(如果使用 ,则会自动发生@gen.coroutine),这使得它们可以在没有gen.Taskor的协程中使用gen.Callback

于 2013-09-23T04:03:44.057 回答