【优化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之控制台(console)颜色显示

    #coding=utf-8 import ctypes,sys STD_INPUT_HANDLE = -10 STD_OUTPUT_HANDLE = -11 STD_ERROR_HANDLE = -1 ...

  2. Java面向对象 继承(上)

       Java面向对象 继承 知识概要:         (1)继承的概述 (2)继承的特点 (3)super关键字 (4)函数覆盖 (5) 子类的实例化过程 (6) final关键字 (1)继承 ...

  3. 一些精妙的sql语句收集

    --1.说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用) --法一: select * into b from a where 1<>1 --法二: select ...

  4. wpf 制作必输项的*标记

    直接引用帮助文档上的话吧,以免下次忘记! AdornedElementPlaceholder 类 .NET Framework 3.5   其他版本   此主题尚未评级 - 评价此主题   更新:20 ...

  5. Swift搭建服务端

    原文:Hello Server Side Swift 作者:Logan Wright 译者:CocoaChina--kmyhy(博客) 自从苹果官方发布了一个 Swift 的 Linux 开源版本之后 ...

  6. 吾八哥学Python(三):了解Python基础语法(上)

    学习一门开发语言首先当然是要熟悉它的语法了,Python的语法还算是比较简单的,这里从基础的开始了解一下. 标识符1.第一个字符必须是字母表中字母或下划线'_'.2.标识符的其他的部分有字母.数字和下 ...

  7. ASP.NET没有魔法——ASP.NET MVC IoC

    之前的文章介绍了MVC如何通过ControllerFactory及ControllerActivator创建Controller,而Controller又是如何通过ControllerBase这个模板 ...

  8. 【NOIP2016提高组】 Day2 T2 蚯蚓

    题目传送门:https://www.luogu.org/problemnew/show/P2827 自测时被题面所误导...,题面中说逢t的倍数才输出答案,以为有什么玄妙的方法直接将m次操作变成了m/ ...

  9. CMake vs Make对比

    程序员现在已经使用了CMake和Make了很久.当您加入大公司或开始使用大型代码库开发项目时,您需要处理所有这些构建.你必须看到这些“CMakeLists.txt”文件浮动.你应该在终端上运行“cma ...

  10. java8Stream原理深度解析

    Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...