Asynchronous programming using Tornado's Gen.coroutine

Source: Internet
Author: User
Tags mongodb driver

After the release of Tornado3, the concept of coroutine was strengthened, and in asynchronous programming, it replaced the original Gen.engine and became the present gen.coroutine. This decorator is intended to simplify asynchronous programming in tornado. Avoid writing callback functions that make development more consistent with normal logical thinking.
A simple example is as follows:
  1. Class Maindhandler(Web. RequestHandler):
  2. @asynchronous
  3. @gen. Coroutine
  4. def Post(self):
  5. Client = asynchttpclient()
  6. Resp = yield client. Fetch(HTTPS://API. GitHub. COM/users")
  7. if Resp.code = = 200:
  8. RESP = Escape.json_decode (resp.body)
  9. Self.write (Json.dumps (resp, indent=4, separators= (', ', ': ')))
  10. Else
  11. Resp = {"message": "error when fetch something"}
  12. Self.write (Json.dumps (resp, indent=4, separators={', ', ': ')))
  13. Self.finish ()

After the yield statement, Ioloop registers the event until RESP returns and resumes execution. This process is asynchronous. Using Json.dumps here instead of using Tornado's escape.json_encode is because when building a restful API, it is often accessed from the browser to get JSON-formatted data. After you format the data using Json.dumps, it is more friendly when the browser side displays the view. The Github API is the user of this style. In fact, Escape.json_encode is a simple package for json.dumps, and when I ask for more versatility with the pull request package, the author's answer to escape is not intended to provide full JSON functionality, and the user can use the JSON module directly.

gen.coroutine principle

In a previous blog post about the asynchronous nature of using tornado, you must use an asynchronous library. Otherwise, a single process is blocked and does not achieve an asynchronous effect at all. The most common in Tornado asynchronous libraries is the self-contained asynchttpclient, and the OpenID login authentication interface implemented on top of it. Additional asynchronous libraries can be found here. Including the use of more MongoDB driver.

After the 3.0 release, the Gen.coroutine module appears to be more prominent. The Coroutine decorator allows asynchronous programming that would otherwise be callbacks to look like synchronous programming. This is the use of the Send function of the generator in Python. In the generator, the yield keyword tends to be compared to return in the normal function. It can be used as an iterator to return yield results using next (). But there is another use of the generator, which is using the Send method. The result of yield can be assigned to a variable inside the generator, and this value is sent through the external generator client. To give an example:

  1. def Test_yield():
  2. Pirnt "Test Yeild"
  3. Says = (yield)
  4. print says
  5. If __name__ = = "__main__":
  6. Client = Test_yield()
  7. Client. Next()
  8. Client. Send("Hello World")

The output results are as follows:
Test Yeild
Hello World

The function that is already running is suspended until the client calling it uses the Send method, and the original function continues to run. The Gen.coroutine method here is to execute the required operation asynchronously, then wait for the result to return, then send to the original function, the original function will continue to execute, so that the synchronous writing code to achieve the effect of asynchronous execution.

Tornado Asynchronous Programming

Asynchronous programming that uses Coroutine to implement function separation. Specific as follows:
  1. @gen. Coroutine
  2. def Post(self):
  3. Client = asynchttpclient()
  4. Resp = yield client. Fetch("Https://api.github.com/users")
  5. if resp = = :
  6. Body = escape. Json_decode(resy. Body)
  7. else:
  8. Body = {"message": "client fetch error"}
  9. Logger. Error("Client fetch error%d,%s" % (resp). Code, resp. Message))
  10. Self. Write(escape. Json_encode(body))
  11. Self. Finish()

This can be changed after the function is changed;
  1. @gen. Coroutime
  2. def Post(self):
  3. Resp = yield GetUser()
  4. Self. Write(resp)
  5. @gen. Coroutine
  6. def GetUser():
  7. Client = asynchttpclient()
  8. Resp = yield client. Fetch("Https://api.github.com/users")
  9. if resp. Code = = :
  10. Resp = escape. Json_decode(resp. Body)
  11. else:
  12. Resp = {"message": "Fetch client Error"}
  13. Logger. Error("Client fetch error%d,%s" % (resp). Code, resp. Message))
  14. raise gen. Return(resp)

Here, when the asynchronous encapsulated in a function, not like a normal program with the return keyword to return, Gen module provides a Gen. The return method. is achieved through the Raise method. This is also related to the way it is implemented using the generator.

use Coroutine to run timed tasks

There is one such method in tornado:

Tornado.ioloop.IOLoop.instance (). Add_timeout ()

The method is a non-blocking version of Time.sleep, which accepts two parameters: a length of time and a function. Represents how much time is called after the function. Here it is based on ioloop, so it is non-blocking. This method is more used in long-client connection and callback function programming. But using it to run some timed tasks is helpless. Usually run-time tasks are also not necessary to use to it. But when I was using Heroku, I found that I could only use a simple Web application hosting without registering a credit card. You cannot add timed tasks to run. So I came up with such a method. Here, I mostly use it to crawl data over a period of time through the GitHub API interface. The large self-use method is as follows:

Decorative Device
  1. def sync_loop_call(delta= * ):
  2. """
  3. Wait for func down then process add_timeout
  4. """
  5. def wrap_loop(func):
  6. @wraps(func)
  7. @gen. Coroutine
  8. def wrap_func(*args, * *Kwargs):
  9. Options. Logger. Info("function%r start at%d" %
  10. (func. __name__, int(time. Time() )))
  11. try:
  12. yield func(*args, * *kwargs)
  13. except Exception, e:
  14. Options. Logger. Error("function%r Error:%s" %
  15. (func. __name__, e))
  16. Options. Logger. Info("function%r end at%d" %
  17. (func. __name__, int(time. Time() )))
  18. Tornado. Ioloop. Ioloop. Instance(). Add_timeout(
  19. DateTime. Timedelta(milliseconds=Delta),
  20. Wrap_func)
  21. return wrap_func
  22. return wrap_loop

Task Function
    1. @sync_loop_call(delta=Ten * )
    2. def worker():
    3. """
    4. Do something
    5. """

Add a task
    1. if __name__ = = "__main__":
    2. Worker()
    3. App. Listen(options. Port)
    4. Tornado. Ioloop. Ioloop. Instance(). Start()

After doing this, when the Web application is started, the scheduled task will run with it, and because it is event-based and asynchronous, it does not affect the normal operation of the Web service, and the task must not be blocked or computationally intensive. I'm mainly crawling data here, and using Tornado's own asynchronous fetch method.

In the Sync_loop_call decorator, I added a @gen.coroutine adorner on the Wrap_func function, which ensures that only the Yeild function is executed before the add_timeout operation is performed. If there is no @gen.coroutine adorner. Then the add_timeout will be executed without waiting for Yeild to return.

A complete example can be found on my GitHub, a project built on Heroku. Used to show GitHub user activity rankings and user area distributions. You can access the Github-data view. As the domestic Heroku by the wall, need to FQ to access.

Summary

Tornado is a non-blocking Web server as well as a web framework, but only using an asynchronous library in use can really play its asynchronous advantage, sometimes because the app itself is not very demanding, and if it is not blocking is particularly serious, there is no problem. In addition to using the Coroutine module for asynchronous programming, when a function is encapsulated in a function, in the function, even if there is an error, if not to capture the words will not be thrown, which is very difficult to debug.

Asynchronous programming using Tornado's Gen.coroutine

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.