问题
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