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