问题描述
这是一个愚蠢的websocket时钟的有趣之处:
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)
我很清楚第一种形式(只有一个 yield
表达式)发生了什么,但是为什么我必须将控制权交给Tornado来创建 gen.Callback
对象?
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?
一个单独的 yield
表达式如何等效于两个 yield
表达式?难道不能控制两次龙卷风的收益吗?但是,在 gen.Task
表单中,我只产生一次控制!
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!
推荐答案
调用 yield gen.Callback
时,它会短暂地将控制权转移到Tornado,但是Tornado立即返回您的代码.这只是与协程调度程序进行通信的一种方式,而无需使用全局(或线程局部)变量.它使用这种奇怪的模式,因此可以与 gen
模块之前的库一起使用,而对协程一无所知.对于较新的代码(自Tornado 3.0起),推荐的模式是异步函数返回 Future
(如果使用 @ gen.coroutine
,则会自动发生),这将使它们可以在没有 gen.Task
或 gen.Callback
的协程中使用.
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
.
这篇关于扩展tornado.gen.Task的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!