Go Tornado Get/post request Asynchronous Processing framework Analysis

Source: Internet
Author: User

transferred from: http://m.blog.csdn.net/blog/joeyon/41956027first of all, the environment, python2.7,tornado3.0

Then this article discusses not how the tornado layer handles socket communication with Epoll, but how to process get/post requests asynchronously at the application level. Here is the text:

At the same time, apply @tornado.web.asynchronous and on the Get or POST method processing @tornado. Gen.engineAdorners, which can be very convenient and asynchronous methods with callback parameters to implement non-blocking request processing. This is not the case for the official example, because the official example would have been to use an asynchronous HTTP client to pull the data and then go to the callback function execution, the code for the discussion HTTP client is not within the scope of this article. So I use a simple function to demonstrate, and this is more to illustrate the problem. Class Registerhandler(Basehandler. Basehandler): @tornado. Web.asynchronous @tornado. Gen.engineDef Get( Self, *arg, **args): Response = yield Tornado.gen.Task ( Self. method_while) Print "Response", response Self. Finish () def Method_while( Self, *arg, **args): Callback (1)  This is what I wrote a request to process the Handler,get request to add the two adorners, the first adorner indicates that the GET function is not automatically cut off the output stream, you need to explicitly call the finish method. This decorator needs to be used with @tornado.gen.engine. The point is, to see @tornado.gen.engine's source def. engine(func): @functools. Wraps(func) def wrapper(*args, **kwargs): Runner = None def handle_exception(Typ, value, TB):             if runner is  not None:                 return runner.handle_exception (Typ, value, TB)              return False        with  Exceptionstackcontext (handle_exception)  as deactivate:             Gen = func (*args, **kwargs)              if isinstance (gen, types. Generatortype):                Runner = runner (Gen, deactivate)                  Runner.run ()             &nBsp;   return            assert  gen is none, gen            deactivate ()     return wrapper (I deleted the original comment)   We can look directly inside the WITH statement: Gen = func (*args, **kwargs) if  isinstance (gen, types. Generatortype):
runner = runner (Gen, deactivate) Runner.run () return

Gen is our Get method, Gen=fun (*args,**kwargs) is equivalent to Gen=get (*args,**kwargs), and the Get method execution results are returned to Gen? No~no! The Get method has yield, which means that get (*args,**kwargs) returns the data of a generator type Generatortype, which is not executed immediately and needs to call his next or send method to execute to the next yield method. The specific usage of the generator and its send and next is beyond the scope of this article, please consult the official documentation. Can see it new a runner,gen passed in, and then execute the Run method, we follow the code of the Runner class's Run method: Def Run( Self): If Self. Running or Self. Finished: #判断是否是在运行中或者已经结束, if you are returning return try immediately: Self. Running = True #让状态为运行中 while true: #进入循环 if Self. Exc_info is None: #上次循环没有异常 try:if not Self. Yield_point.is_ready (): #判断key是否可用 return next = Self. Yield_point.get_result () #获取yield表达式的结果给next except Exception: Self. Exc_info = Sys.exc_info () try:if Self. Exc_info is not None: Self. had_exception = True Exc_info = Self. exc_info Self. Exc_info = None yielded = Self. Gen.throw (*exc_info) else:yielded = Self. Gen.send (Next) #如果上次没异常, the Get function continues execution, where the task object is returned to yielded, which is equivalent to iterating over the task (the most up-to-date code snippet) and assigning the task to yielded each time it executes to yield Except stopiteration: #如果没有可以执行的了, back Self. finished = True If Self. Pending_callbacks and not Self. Had_exception:raise Leakedcallbackerror ( "finished without waiting for callbacks%r"% Self. pending_callbacks) Self. Deactivate_stack_context () Self. Deactivate_stack_context = None return except Exception: Self. finished = True Raise if isinstance (yielded, list): yielded = Multi ( yielded) if isinstance (yielded, yieldpoint): #如果yielded为Task类型 (Task inherits from Yieldpoint) Self. Yield_point = yielded try: Self. Yield_point.start ( Self) #执行task的start方法 except Exception: Self. Exc_info = Sys.exc_info () Else: Self. Exc_info = (Badyielderror ( "yielded unknown object%r"% yielded),) finally: Self. running = False The specific steps can be seen in the comments in the above code, here we continue to see the Start method of the task: class Task(Yieldpoint): (Omit other code) def Start( Self, runner): Self. Runner = Runner Self. Key = Object () Runner.register_callback ( Self. Key) Self. kwargs[ "Callback"] = Runner.result_callback ( Self. Key) Self. Func (* Self. Args, * * Self. Kwargs) (omit other code) here the Func method is the topmost method_while, passing a callback parameter in: Runner.result_callback ( Self. key), and then execute the method. In order to discuss the effect of this callback parameter, we assume that this parameter is not used in this method_while method, that is, the Callback:start method is returned after Method_while executes. Continue executing the second pass of that loop in the runner Run method, which will be directly in this line if not Self. Yield_point.is_ready (): #判断key是否可用 return is returned directly, because the key corresponding to the value in results is none. Here are two nouns, where are results and key,result? is a field of runner, from the constructor of the runner below you can see that results is a dictionary: class Runner(object): Def __init__( Self, Gen, Deactivate_stack_context): (Omit other code) Self. Pending_callbacks = Set () Self. Results = {} (omitting other code) so how is the key set to results in this dictionary? Is in the Start method of the task, Runner.register_callback ( Self. key), the specific code can look at the above task class. This register_callback is a bit around, it sets the key to Pending_callbacks inside, this pending_callbacks is a set type, that is, a non-repeatable collection, The purpose of this set is to determine the existence of a key from this point each time, and key exists to indicate that there is a task to execute. In the above run method to determine whether key is available, is_ready each time will first determine whether the key is in this pending_callbacks, no direct report exception, some words will go to results to fetch results. We can see that results has always been empty ah, when to set the value of it?? Is the callback method that we did not execute in the method_while, namely Runner.result_callback ( Self. Key): def Result_callback( Self, key): def Inner(*args, **kwargs): If Kwargs or Len (args) > 1:result = Arguments (args, Kwargs) el If Args:result = args[0] Else:result = None Self. Set_result (key, result) return inner can be seen, he callback the actual invocation of the argument list is written into the results, return to the yield expression value response. So we find that it is important to execute the callback in the parameter in the custom method, write the data you want to return into the callback parameter, the value of the yield expression will be this parameter, and then the Run method proceeds to the next yield until the Get method is completed. Like the top example, the print result is: Response 1 Finally, what is the use of this asynchronous scheme? When it comes to asynchrony, newbies will certainly think it is Get/post method blocking is also OK, a GET request come over, get handler function if blocked, is bound to cause the entire server blocked! Do not think this is a relative web front-end request of the parallel asynchronous solution, single-threaded tornado after all is a single thread, method blocking, will inevitably lead to server blocking, no doubt. This asynchronous is relative to the GET request, When the Get method finishes without the adorner @tornado.web.asynchronous, the request is automatically broken, but after the adorner is added, the GET request can return directly and remain connected until the finish method is explicitly called to close the output stream. So the initiation of asynchronous (asynchronous: the matter to the person other than themselves to do, their own no matter) solution, get method directly return, to other functions to do, and then come back. Plus @tornado.gen.engine just put this idea down, the code is condensed to a minimum, this does not mean that the asynchronous processing function or the Get has a dead loop can also let the server processing other requests, you query the database to spend 10000s, then your server will certainly die 10000s , there are four solutions to this problem: CROUCHDB (with HTTP interface, asynchronous HttpClient call), optimizing current database, asynchronous HttpClient WebService, and thread. Recommend the second third, followed by the fourth, and finally the first (reason does not explain, seemingly crouchdb word of mouth is not good, I do not love, MONGO party floated). Even if it's an asynchronous httpclient, it's like this.
def handle_request (response):    if Response.error:        print "error:", Response.error    else:        print Response.bodyhttp_client = Asynchttpclient () http_client.fetch ("http://www.google.com/", Handle_request)
Also just after the fetch no matter how the socket pulls the data, the callback is also to be executed on this thread! Elsewhere, if there is a time-consuming operation or a dead loop, the data it pulls over is never in the Handle_request function.

Go Tornado Get/post request Asynchronous Processing framework Analysis

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.