【优化tornado阻塞任务的三个选择】

1、优化阻塞的任务,使其执行时间更快。经常由于是一个DB的慢查询,或者复杂的上层模板导致的,这个时候首要的是加速这些任务,而不是优化复杂的webserver。可以提升99%的效率。

2、开启一个单独的线程或者进程执行耗时任务。这意味着对于IOLoop来说,可以开启另一个线程(或进程)处理off-loading任务,这样它就可以再接收其他请求了,而不是阻塞住。

3、使用异步的驱动或者库函数来执行任务,例如gevent , motor

【例子1】

import time

import tornado.ioloop
import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self):
self.write("Hello, world %s" % time.time()) class SleepHandler(tornado.web.RequestHandler): def get(self, n):
time.sleep(float(n))
self.write("Awake! %s" % time.time()) application = tornado.web.Application([
(r"/", MainHandler),
(r"/sleep/(\d+)", SleepHandler),
]) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

这样在一个tab页中开启http://localhost:8888/sleep/10,同时在另一个tab页访问http://localhost:8888/,会发现没有打印"Hello World"直到第一个页面完成为止。实际上,第一个调用将IOLoop阻塞住了,导致其无法响应第二个请求。

【例子2——非阻塞模式】

from concurrent.futures import ThreadPoolExecutor
from functools import partial, wraps import tornado.ioloop
import tornado.web EXECUTOR = ThreadPoolExecutor(max_workers=4) def unblock(f): @tornado.web.asynchronous
@wraps(f)
def wrapper(*args, **kwargs):
self = args[0] def callback(future):
self.write(future.result())
self.finish() EXECUTOR.submit(
partial(f, *args, **kwargs)
).add_done_callback(
lambda future: tornado.ioloop.IOLoop.instance().add_callback(
partial(callback, future))) return wrapper class SleepHandler(tornado.web.RequestHandler): @unblock
def get(self, n):
time.sleep(float(n))
return "Awake! %s" % time.time()

unblock修饰器将被修饰函数提交给线程池,返回一个future。在future中添加一个callback函数,并将控制权交给IOLoop。

这个回调函数最终将调用self.finish,并结束此次请求。

Note:这个修饰器函数本身还需要被tornado.web.asynchronous修饰,为了是避免调用self.finish太快。

self.write不是线程安全(thread-safe)的,因此避免在主线程中处理future的结果。

当你使用@tornado.web.asynchonous装饰器时,Tornado永远不会自己关闭连接,需要显式的self.finish()关闭

【完整的demo】

from concurrent.futures import ThreadPoolExecutor
from functools import partial, wraps
import time import tornado.ioloop
import tornado.web EXECUTOR = ThreadPoolExecutor(max_workers=4) def unblock(f): @tornado.web.asynchronous
@wraps(f)
def wrapper(*args, **kwargs):
self = args[0] def callback(future):
self.write(future.result())
self.finish() EXECUTOR.submit(
partial(f, *args, **kwargs)
).add_done_callback(
lambda future: tornado.ioloop.IOLoop.instance().add_callback(
partial(callback, future))) return wrapper class MainHandler(tornado.web.RequestHandler): def get(self):
self.write("Hello, world %s" % time.time()) class SleepHandler(tornado.web.RequestHandler): @unblock
def get(self, n):
time.sleep(float(n))
return "Awake! %s" % time.time() class SleepAsyncHandler(tornado.web.RequestHandler): @tornado.web.asynchronous
def get(self, n): def callback(future):
self.write(future.result())
self.finish() EXECUTOR.submit(
partial(self.get_, n)
).add_done_callback(
lambda future: tornado.ioloop.IOLoop.instance().add_callback(
partial(callback, future))) def get_(self, n):
time.sleep(float(n))
return "Awake! %s" % time.time() application = tornado.web.Application([
(r"/", MainHandler),
(r"/sleep/(\d+)", SleepHandler),
(r"/sleep_async/(\d+)", SleepAsyncHandler),
]) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

【ThreadPoolExecutor】

上面涉及到ThreadPoolExecutor两个方法,初始化以及submit,查看帮助

class ThreadPoolExecutor(concurrent.futures._base.Executor)
| Method resolution order:
| ThreadPoolExecutor
| concurrent.futures._base.Executor
| __builtin__.object
|
| Methods defined here:
|
| __init__(self, max_workers)
| Initializes a new ThreadPoolExecutor instance.
|
| Args:
| max_workers: The maximum number of threads that can be used to
| execute the given calls.
|
| submit(self, fn, *args, **kwargs)
| Submits a callable to be executed with the given arguments.
|
| Schedules the callable to be executed as fn(*args, **kwargs) and returns
| a Future instance representing the execution of the callable.
|
| Returns:
| A Future representing the given call.

1、max_workers可以处理给定calls的最大线程数目,如果超过这个数目会怎么样呢??

2、submit调用fn(*args, **kwargs),返回一个Future的实例

【Future】

Help on class Future in module concurrent.futures._base:

class Future(__builtin__.object)
| Represents the result of an asynchronous computation.
|
| Methods defined here:
|
| __init__(self)
| Initializes the future. Should not be called by clients.
|
| __repr__(self)
|
| add_done_callback(self, fn)
| Attaches a callable that will be called when the future finishes.
|
| Args:
| fn: A callable that will be called with this future as its only
| argument when the future completes or is cancelled. The callable
| will always be called by a thread in the same process in which
| it was added. If the future has already completed or been
| cancelled then the callable will be called immediately. These
| callables are called in the order that they were added.

  

【参考文献】

1、http://lbolla.info/blog/2013/01/22/blocking-tornado

2、http://www.tuicool.com/articles/36ZzA3

tornado的非异步阻塞模式的更多相关文章

  1. Python开发【Tornado】:异步Web服务(二)

    真正的 Tornado 异步非阻塞 前言: 其中 Tornado 的定义是 Web 框架和异步网络库,其中他具备有异步非阻塞能力,能解决他两个框架请求阻塞的问题,在需要并发能力时候就应该使用 Torn ...

  2. TCP同步与异步及阻塞模式,多线程+阻塞模式,非阻塞模式简单介绍

    首先我简单介绍一下同步TCP编程 与异步TCP编程. 在服务端我们通常用一个TcpListener来监听一个IP和端口.客户端来一个请求的连接,在服务端可以用同步的方式来接收,也可以用异步的方式去接收 ...

  3. 同步异步阻塞非阻塞Reactor模式和Proactor模式 (目前JAVA的NIO就属于同步非阻塞IO)

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...

  4. 同步与异步 & 阻塞与非阻塞

    在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 一.同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用 ...

  5. PHP非阻塞模式 (转自 尘缘)

    让PHP不再阻塞当PHP作为后端处理需要完成一些长时间处理,为了快速响应页面请求,不作结果返回判断的情况下,可以有如下措施: 一.若你使用的是FastCGI模式,使用fastcgi_finish_re ...

  6. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  7. Socket 阻塞模式和非阻塞模式

    阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...

  8. 转:PHP非阻塞模式

    你可以任意转摘“PHP非阻塞模式”,但请保留本文出处和版权信息.作者:尘缘,QQ:130775,来源:http://www.4wei.cn/archives/1002336 让PHP不再阻塞当PHP作 ...

  9. 深入 CSocket 编程之阻塞和非阻塞模式

    有时,花上几个小时阅读.调试.跟踪优秀的源码程序,能够更快地掌握某些技术关键点和精髓.当然,前提是对这些技术大致上有一个了解. 我通过几个采用 CSocket 类编写并基于 Client/Server ...

随机推荐

  1. Hibernate 学习笔记 - 2

    五.映射一对多关联关系 1. 单向多对一 即 单向 n-1 1)单向 n-1 关联只需从 n 的一端可以访问 1 的一端 ① 域模型: 从 Order 到 Customer 的多对一单向关联需要在Or ...

  2. python安装(python2.7)

    1.下载python 进入官网下载安装 点击打开链接(官网地址:https://www.python.org/downloads/),进入官网后根据自己需求选择python2 或者 python3 2 ...

  3. win10 uwp 绘图 Line 控件使用

    本文主要讲一个在绘图中,我们会有一个基础的控件,Line.控件的基本使用和他能做出的我们很多时候需要的界面. 虽然是一个简单控件,但是可以做出很诡异的很好看的UI. 首先,我们要知道,Line就是画直 ...

  4. PyCharm 2017 官网 下载 安装 设置 配置 (主题 字体 字号) 使用 入门 教程

    一.安装 Python 3.6 首先,要安装好 Python 3.6.如果你还没有安装,可以参考咪博士之前的教程 Python 3.6.3 官网 下载 安装 测试 入门教程 (windows) 二.官 ...

  5. 使用bitset实现毫秒级查询(二)

    在上一篇中我们了解了bitset索引的基本用法,本篇开始学习bitset索引更新及一些复杂查询. 1.bitset索引更新   因为我们的数据是在系统启动时全部加载进内存,所以当数据库数据发生变化时要 ...

  6. vux 组件打造手机端项目

    其实,我用vux组件的过程是这样的,哇!太方便了!!功能好全!!太简单了!!然后,就各种"跳坑".以下排坑环节. 1.安装vux:cnpm i -S vux;   比较顺利吧. 2 ...

  7. 用 Smali 手写一个可运行的 HelloWorld!!!

    一.前言 Android 的 App 实际上并不是运行在 Java 虚拟机中,而是运行在 Dalvik 虚拟机中.Dalvik 虚拟机对 Java 虚拟机做了一些额外的优化,让它更适用于移动设备.而 ...

  8. MongoDB备份恢复与导出导入

    说明:本文所有操作均在win7下的MongoDB3.4.4版本中进行. 一.备份与恢复 1. 备份: mongodump -h IP --port 端口 -u 用户名 -p 密码 -d数据库 -o 文 ...

  9. 在 ASP.NET Core 中使用 SignalR

    https://weblogs.asp.net/ricardoperes/signalr-in-asp-net-core 作者:Ricardo Peres 译者:oopsguy.com 介绍 Sign ...

  10. 腾讯云VS AWS :云存储网关性能谁更优?

    p { text-indent: 2em }    随着企业规模的扩大及业务的扩展,现有IT基础设施特别是存储设备无法满足爆炸性的数据增长,企业 IT 部门为了解决该问题,往往面临市场上多种存储产品及 ...