tornado的非异步阻塞模式
【优化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的非异步阻塞模式的更多相关文章
- Python开发【Tornado】:异步Web服务(二)
真正的 Tornado 异步非阻塞 前言: 其中 Tornado 的定义是 Web 框架和异步网络库,其中他具备有异步非阻塞能力,能解决他两个框架请求阻塞的问题,在需要并发能力时候就应该使用 Torn ...
- TCP同步与异步及阻塞模式,多线程+阻塞模式,非阻塞模式简单介绍
首先我简单介绍一下同步TCP编程 与异步TCP编程. 在服务端我们通常用一个TcpListener来监听一个IP和端口.客户端来一个请求的连接,在服务端可以用同步的方式来接收,也可以用异步的方式去接收 ...
- 同步异步阻塞非阻塞Reactor模式和Proactor模式 (目前JAVA的NIO就属于同步非阻塞IO)
在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...
- 同步与异步 & 阻塞与非阻塞
在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 一.同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用 ...
- PHP非阻塞模式 (转自 尘缘)
让PHP不再阻塞当PHP作为后端处理需要完成一些长时间处理,为了快速响应页面请求,不作结果返回判断的情况下,可以有如下措施: 一.若你使用的是FastCGI模式,使用fastcgi_finish_re ...
- 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor
开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...
- Socket 阻塞模式和非阻塞模式
阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...
- 转:PHP非阻塞模式
你可以任意转摘“PHP非阻塞模式”,但请保留本文出处和版权信息.作者:尘缘,QQ:130775,来源:http://www.4wei.cn/archives/1002336 让PHP不再阻塞当PHP作 ...
- 深入 CSocket 编程之阻塞和非阻塞模式
有时,花上几个小时阅读.调试.跟踪优秀的源码程序,能够更快地掌握某些技术关键点和精髓.当然,前提是对这些技术大致上有一个了解. 我通过几个采用 CSocket 类编写并基于 Client/Server ...
随机推荐
- Hibernate 学习笔记 - 2
五.映射一对多关联关系 1. 单向多对一 即 单向 n-1 1)单向 n-1 关联只需从 n 的一端可以访问 1 的一端 ① 域模型: 从 Order 到 Customer 的多对一单向关联需要在Or ...
- python安装(python2.7)
1.下载python 进入官网下载安装 点击打开链接(官网地址:https://www.python.org/downloads/),进入官网后根据自己需求选择python2 或者 python3 2 ...
- win10 uwp 绘图 Line 控件使用
本文主要讲一个在绘图中,我们会有一个基础的控件,Line.控件的基本使用和他能做出的我们很多时候需要的界面. 虽然是一个简单控件,但是可以做出很诡异的很好看的UI. 首先,我们要知道,Line就是画直 ...
- PyCharm 2017 官网 下载 安装 设置 配置 (主题 字体 字号) 使用 入门 教程
一.安装 Python 3.6 首先,要安装好 Python 3.6.如果你还没有安装,可以参考咪博士之前的教程 Python 3.6.3 官网 下载 安装 测试 入门教程 (windows) 二.官 ...
- 使用bitset实现毫秒级查询(二)
在上一篇中我们了解了bitset索引的基本用法,本篇开始学习bitset索引更新及一些复杂查询. 1.bitset索引更新 因为我们的数据是在系统启动时全部加载进内存,所以当数据库数据发生变化时要 ...
- vux 组件打造手机端项目
其实,我用vux组件的过程是这样的,哇!太方便了!!功能好全!!太简单了!!然后,就各种"跳坑".以下排坑环节. 1.安装vux:cnpm i -S vux; 比较顺利吧. 2 ...
- 用 Smali 手写一个可运行的 HelloWorld!!!
一.前言 Android 的 App 实际上并不是运行在 Java 虚拟机中,而是运行在 Dalvik 虚拟机中.Dalvik 虚拟机对 Java 虚拟机做了一些额外的优化,让它更适用于移动设备.而 ...
- MongoDB备份恢复与导出导入
说明:本文所有操作均在win7下的MongoDB3.4.4版本中进行. 一.备份与恢复 1. 备份: mongodump -h IP --port 端口 -u 用户名 -p 密码 -d数据库 -o 文 ...
- 在 ASP.NET Core 中使用 SignalR
https://weblogs.asp.net/ricardoperes/signalr-in-asp-net-core 作者:Ricardo Peres 译者:oopsguy.com 介绍 Sign ...
- 腾讯云VS AWS :云存储网关性能谁更优?
p { text-indent: 2em } 随着企业规模的扩大及业务的扩展,现有IT基础设施特别是存储设备无法满足爆炸性的数据增长,企业 IT 部门为了解决该问题,往往面临市场上多种存储产品及 ...