这是一个愚蠢的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
表达式?一定不能两次控制龙卷风的产量?然而,在gen.Task
形式中,我只能控制一次!
答案 0 :(得分:0)
当你致电yield gen.Callback
时,它会简单地将控制转移到Tornado,但Tornado会立即返回你的代码。它只是一种与协程调度程序通信而不使用全局(或线程局部)变量的方法。它使用这种奇怪的模式,因此它可以使用早于gen
模块的库,并且不知道任何关于协程的知识。对于较新的代码(从Tornado 3.0开始),推荐的模式一直是异步函数返回Future
(如果你使用@gen.coroutine
会自动发生),这使得它们可以在没有{{1}的协同程序中使用}或gen.Task
。