【优化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. Python之scrapy实例1

    下文参考:http://www.jb51.net/article/57183.htm 个人也是稍加整理,修改其中的一些错误,这些错误与scrapy版本选择有关,个环境:Win7x64_SP1 + Py ...

  2. scala PartialFunction

    1.orElse和andThen的区别 源码如下,区别很明显,orElse是并列的关系,而andThen是调用者的结果作为k的输入. trait PartialFunction[-A, +B] ext ...

  3. 关于form表单上传图片的一些记录

    jsp页面 <form class="form-horizontal" role="form" action="brandAction_addB ...

  4. Python学习笔记(六)

    Python学习笔记(六) Ubuntu重置root密码 Ubuntu 16.4 目录结构 Ubuntu 命令讲解 1. Ubuntu重置root密码 启动系统,显示GRUB选择菜单(如果默认系统启动 ...

  5. hdu 4751 Divide Groups bfs (2013 ACM/ICPC Asia Regional Nanjing Online 1004)

    SDUST的训练赛 当时死磕这个水题3个小时,也无心去搞其他的 按照题意,转换成无向图,预处理去掉单向的边,然后判断剩下的图能否构成两个无向完全图(ps一个完全图也行或是一个完全图+一个孤点) 代码是 ...

  6. servlet过滤器简化版

    什么是过滤器 在struts2 中集成了过滤器,并可以根据需要选择合适自己的过滤器进行配置 , 过滤器:是基于函数回调的,运用java中的反射机制工作在struts2只能对于action起作用,在se ...

  7. 快速排序算法分析--C++版

    快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试喜欢考这个. 快速排序是C.R.A.Hoar ...

  8. 【转】花开正当时,十四款120/128GB SSD横向评测

    原文地址:http://www.expreview.com/19604-all.html SSD横评是最具消费指导意义的评测文章,也是各类热门SSD固态硬盘的决斗疆场.SSD评测在行业内已经有不少网站 ...

  9. ELK系列~log4-nxlog-Fluentd-elasticsearch写json数据需要注意的几点

    经验与实践 前两篇文章里我们介绍了nxlog的日志收集和转发<ELK系列~Nxlog日志收集加转发(解决log4日志换行导致json转换失败问题)>,今天我们主要总结一下,在与log4和f ...

  10. R学习笔记 第二篇:矩阵、数组和列表

    向量是一维的,只有长度(行),没有其他维度.R中存在更高维度的对象,他们是矩阵,数据框,数组.这些对象的下标都是使用中括号[],第一个维度是row,第二个维度是column,依次类推,[row,col ...