Asynchronous programming can be tricky for beginners, therefore I think it’s useful to iron some basic concepts to avoid common pitfalls. For an explanation about generic asynchronous programming, I recommend you one of the many resourcesonline. I will focus solely on asynchronous programming in Tornado.

From Tornado’s homepage:

FriendFeed’s web server is a relatively simple, non-blocking web server written in Python. The FriendFeed application is written using a web framework that looks a bit like web.py or Google’s webapp, but with additional tools and optimizations to take advantage of the non-blocking web server and tools. Tornado is an open source version of this web server and some of the tools we use most often at FriendFeed. The framework is distinct from most mainstream web server frameworks (and certainly most Python frameworks) because it is non-blocking and reasonably fast. Because it is non-blocking and uses epoll or kqueue, it can handle thousands of simultaneous standing connections, which means the framework is ideal for real-time web services. We built the web server specifically to handle FriendFeed’s real-time features every active user of FriendFeed maintains an open connection to the FriendFeed servers. (For more information on scaling servers to support thousands of clients, see The C10K problem.)

The first step as a beginner is to figure out if you really need to go asynchronous. Asynchronous programming is more complicated that synchronous programming, because, as someone described, it does not fit human brain nicely.

You should use asynchronous programming when your application needs to monitor some resources and react to changes in their state. For example, a web server sitting idle until a request arrives through a socket is an ideal candidate. Or an application that has to execute tasks periodically or delay their execution after some time. The alternative is to use multiple threads (or processes) to control multiple tasks and this model becomes quickly complicated.

The second step is to figure out if you can go asynchronous. Unfortunately in Tornado, not all the tasks can be executed asynchronously.

Tornado is single threaded (in its common usage, although it supports multiple threads in advanced configurations), therefore any “blocking” task will block the whole server. This means that a blocking task will not allow the framework to pick the next task waiting to be processed. The selection of tasks is done by the IOLoop, which, as everything else, runs in the only available thread.

For example, this is a wrong way of using IOLoop:

  import time
  from tornado.ioloop import IOLoop
  from tornado import gen
   
   
  def my_function(callback):
  print 'do some work'
  # Note: this line will block!
  time.sleep(1)
  callback(123)
   
   
  @gen.engine
  def f():
  print 'start'
  # Call my_function and return here as soon as "callback" is called.
  # "result" is whatever argument was passed to "callback" in "my_function".
  result = yield gen.Task(my_function)
  print 'result is', result
  IOLoop.instance().stop()
   
   
  if __name__ == "__main__":
  f()
  IOLoop.instance().start()
view rawasync_generic.py hosted with ❤ by GitHub

Note that blocking_call is called correctly, but, being blocking (time.sleep blocks!), it will prevent the execution of the following task (the second call to the same function). Only when the first call will end, the second will be called by IOLoop. Therefore, the output in console is sequential (“sleeping”, “awake!”, “sleeping”, “awake!”).

Compare the same “algorithm”, but using an “asynchronous version” of time.sleep, i.e. add_timeout:

  # Example of non-blocking sleep.
  import time
  from tornado.ioloop import IOLoop
  from tornado import gen
   
   
  @gen.engine
  def f():
  print 'sleeping'
  yield gen.Task(IOLoop.instance().add_timeout, time.time() + 1)
  print 'awake!'
   
   
  if __name__ == "__main__":
  # Note that now code is executed "concurrently"
  IOLoop.instance().add_callback(f)
  IOLoop.instance().add_callback(f)
  IOLoop.instance().start()
view rawasync_sleep_1.py hosted with ❤ by GitHub

In this case, the first task will be called, it will print “sleeping” and then it will ask IOLoop to schedule the execution of the rest of the routine after 1 second. IOLoop, having the control again, will fire the second call the function, which will print “sleeping” again and return control to IOLoop. After 1 second IOLoop will carry on where he left with the first function and “awake” will be printed. Finally, the second “awake” will be printed, too. So, the sequence of prints will be: “sleeping”, “sleeping”, “awake!”, “awake!”. The two function calls have been executed concurrently (not in parallel, though!).

So, I hear you asking, “how do I create functions that can be executed asynchronously”? In Tornado, every function that has a “callback” argument can be used with gen.engine.TaskBeware though: being able to use Task does not make the execution asynchronous! There is no magic going on: the function is simply scheduled to execution, executed and whatever is passed tocallback will become the return value of Task. See below:

  import time
  from tornado.ioloop import IOLoop
  from tornado import gen
   
   
  def my_function(callback):
  print 'do some work'
  # Note: this line will block!
  time.sleep(1)
  callback(123)
   
   
  @gen.engine
  def f():
  print 'start'
  # Call my_function and return here as soon as "callback" is called.
  # "result" is whatever argument was passed to "callback" in "my_function".
  result = yield gen.Task(my_function)
  print 'result is', result
  IOLoop.instance().stop()
   
   
  if __name__ == "__main__":
  f()
  IOLoop.instance().start()
view rawasync_generic.py hosted with ❤ by GitHub

Most beginners expect to be able to just write: Task(my_func), and automagically execute my_func asynchronously. This is not how Tornado works. This is how Go works! And this is my last remark:

In a function that is going to be used “asynchronously”, only asynchronous libraries should be used.

By this, I mean that blocking calls like time.sleep or urllib2.urlopen or db.query will need to be substituted by their equivalent asynchronous version. For example, IOLoop.add_timeout instead of time.sleepAsyncHTTPClient.fetchinstead of urllib2.urlopen etc. For DB queries, the situation is more complicated and specific asynchronous drivers to talk to the DB are needed. For example: Motor for MongoDB.

Asynchronous programming with Tornado的更多相关文章

  1. Async/Await - Best Practices in Asynchronous Programming

    https://msdn.microsoft.com/en-us/magazine/jj991977.aspx Figure 1 Summary of Asynchronous Programming ...

  2. Async/Await - Best Practices in Asynchronous Programming z

    These days there’s a wealth of information about the new async and await support in the Microsoft .N ...

  3. .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)

    本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...

  4. HttpWebRequest - Asynchronous Programming Model/Task.Factory.FromAsyc

    Posted by Shiv Kumar on 23rd February, 2011 The Asynchronous Programming Model (or APM) has been aro ...

  5. Parallel Programming AND Asynchronous Programming

    https://blogs.oracle.com/dave/ Java Memory Model...and the pragmatics of itAleksey Shipilevaleksey.s ...

  6. Asynchronous Programming Patterns

    Asynchronous Programming Patterns The .NET Framework provides three patterns for performing asynchro ...

  7. C#的多线程——使用async和await来完成异步编程(Asynchronous Programming with async and await)

    https://msdn.microsoft.com/zh-cn/library/mt674882.aspx 侵删 更新于:2015年6月20日 欲获得最新的Visual Studio 2017 RC ...

  8. Asynchronous programming with async and await (C#)

    Asynchronous Programming with async and await (C#) | Microsoft Docs https://docs.microsoft.com/en-us ...

  9. .Net Core自实现CLR异步编程模式(Asynchronous programming patterns)

    最近在看一个线程框架,对.Net的异步编程模型很感兴趣,所以在这里实现CLR定义的异步编程模型,在CLR里有三种异步模式如下,如果不了解的可以详细看MSDN 文档Asynchronous progra ...

随机推荐

  1. mybatis之sql执行有数据但返回结果为null

    最近在使用mybatis查询数据库时,发现在pl/sql中单独执行sql时结果是有值的,但是在程序中拿到的却是null,相关配置如下: (1) <resultMap type="mon ...

  2. MySQLzip压缩文件格式安装教程

    MySQL是一个小巧玲珑但功能强大的数据库,目前十分流行.但是官网给出的安装包有两种格式,一个是msi格式,一个是zip格式的.很多人下了zip格式的解压发现没有setup.exe,面对一堆文件一头雾 ...

  3. https页面证书验证、加密过程简介

    1.服务器向CA机构获取证书(假设这个证书伪造不了),当浏览器首次请求服务器的时候,服务器返回证书给浏览器.(证书包含:公钥+申请者与颁发者的相关信息+签名) 2.浏览器得到证书后,开始验证证书的相关 ...

  4. MVA Prototype Only User License

    This App is only a protetype of MVA WP app, the intent is to demostrate to Leadership person about w ...

  5. putc,fputc,和putchar

    putc()功能和fputc()差不多,一个是宏,一个是函数 putc(int ch,FILE *fp),即将字符ch输出到fp所指的文件中:putchar(char ch),即将字符ch输出到标准输 ...

  6. Texas Instruments matrix-gui-2.0 hacking -- run_script.php

    <?php /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistrib ...

  7. BZOJ5340: [Ctsc2018]假面【概率+期望】【思维】

    LINK 思路 首先考虑减血,直接一个dp做过去,这个部分分不难拿 然后是\(op=1\)的部分 首先因为要知道每个人被打的概率,所以需要算出这个人活着的时候有多少个人活着时概率是什么 那么用\(g_ ...

  8. .NET 中使用 Mutex 进行跨越进程边界的同步

    Mutex 是 Mutual Exclusion 的缩写,是互斥锁,用于防止两个线程同时对计算机上的同一个资源进行访问.不过相比于其他互斥的方式,Mutex 能够跨越线程边界. 本文内容 Mutex ...

  9. Restrictions用法

    HQL运算符 QBC运算符 含义 = Restrictions.eq() 等于equal <>  Restrictions.ne() 不等于not equal >  Restrict ...

  10. 数据库表结构转成设计书,PowerDesigner 表格导出为excel

    数据库中的表导入到PowerDesigner中并转为excel文档 1.打开PowerDesigner12,在菜单中按照如下方式进行操作 file->Reverse Engineer->D ...