transferred from: http://blog.xiaogaozi.org/2012/09/21/understanding-tornado-dot-gen/Understanding Tornado.gen
SEP 21ST, 2012
Tornado @asynchronous
uses decorator to implement asynchronous requests, but the request handler and callback must be separated when used, and the tornado.gen
module can help us do both of these tasks in a function. Here is an example of the official:
12345678 |
ClassGenasynchandler(RequestHandler): @asynchronous @gen. Engine Defget (self Http_client = asynchttpclient () response = yield gen. Task (http_client. Fetch) Do_something_with_response (response) self. Render ( "template.html" )
|
Here the two decorator are slightly more complex, the first one @asynchronous
will be executed first, and its main work is to set RequestHandler
the attribute to the _auto_finish
false
following:
Web.pydownload
123456789 |
DefAsynchronous(Method): @functools. Wraps(Method) DefWrapper(Self,*Args,**Kwargs): IfSelf.Application._wsgi: RaiseException("@asynchronous is not supported for WSGI apps") self. _auto_finish = false with Stack_context. Exceptionstackcontext ( self. _stack_context_handle_exception): return Method (self*args **kwargs) return wrapper
|
Then there is the most important thing, which takes @gen.engine
full advantage of the various features of generator, first of all to see @gen.engine
the implementation (I have omitted some of the code to simplify understanding):
Gen.pydownload
123456789 |
DefEngine(Func): @functools. Wraps(Func) DefWrapper(*Args,**Kwargs): gen = func (*args **kwargs) If isinstance (gentypes generatortype): runner = runner (gen) runner run () return return wrapper
|
local variable Gen
represents in the first paragraph of code, get
function, because get
contains yield
statement, so it becomes a generator. Notice here get
is not executed, but is assigned to Gen
. The next step is to run Runner
Object run
function. In understanding Run
need to know generator is by calling next ()
or send ()
To start, the boot will be encountered , yield
Place hold, and then the yield
return value of the subsequent statement is returned to the caller, Generator is in a paused state at this point, and all contexts will be saved. Call again; next ()
or send ()
will resume generator operation, if you no longer encounter yield The
statement throws stopiteration
exception. The return value is always the same as while the yield
statement itself returns, if it is restored by calling next ()
. None
, and if it is through send ()
The return value depends on the parameters passed to send ()
. For more information on generator, please refer to the official documentation.
In combination with the first paragraph of the sample code, it can be thought that run
the job is to start generator, then get the gen.Task
object and call the function, and so on back to return after the return of the http_client.fetch
generator run, and finally the callback returned value by send()
assigning response
. Here's my simplified code.
Gen.pydownload
123456789 |
DefRun(Self): WhileTrue: IfNotSelf.Yield_point.Is_ready(): Return Next=Self.Yield_point.Get_result() Try: yielded=Selfgen. Send (next) except stopiteration: return Span class= "K" >if isinstance (yielded yieldpoint): self. Yield_point = yielded self.< span class= "n" >yield_point. Start (self)
|
Line 3rd checks to see if the callback is complete and the first run run
is always returned True
. The 5th row gets the return value of the callback, and the same first run returns the None
. will be None
passed to send()
start generator, yielded
which is the gen.Task
object, line 12th calls start
to start running the function we really need to run, corresponding to the sample code is the http_client.fetch
function, and as a Runner
result_callback
callback function 。 As follows:
Gen.pydownload
123456789 |
DefResult_callback(Self,Key): DefInner(*Args,**Kwargs): IfKwargsOrLen(Args)>1: Result=Arguments(Args,kwargs) elif args : result = args [0] else:< Span class= "line", result = none self. Results[key = result self. Run () return inner
|
Called again after the return value of the callback is obtained, run
by get_result
getting the return value, and then returning the return value to the response
code flow that was assigned to continue request handler.
Understanding Tornado.gen