一:正常访问(同一线程中多个请求是同步阻塞状态)

import tornado.ioloop
import tornado.web
import tornado.websocket
import datetime,time class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("main")class IndexHandler(tornado.web.RequestHandler):
def get(self):
time.sleep()
self.write("index") st ={
"template_path": "template",#模板路径配置
"static_path":'static',
} #路由映射 匹配执行,否则404
application = tornado.web.Application([
("/main",MainHandler),
("/index",IndexHandler),
],**st) if __name__=="__main__":
application.listen() #io多路复用
tornado.ioloop.IOLoop.instance().start()

我们先访问index,再去访问main,查看情况

二:使用future模块,实现异步非阻塞

import tornado.ioloop
import tornado.web
import tornado.websocket
import time
from tornado.concurrent import Future class MainHandler(tornado.web.RequestHandler):
def get(self): self.write("main")class IndexHandler(tornado.web.RequestHandler):
def get(self):
future = Future()
tornado.ioloop.IOLoop.current().add_timeout(time.time()+5,self.done) #会在结束后为future中result赋值
yield
future def done(self,*args,**kwargs):
self.write("index")
self.finish()  #关闭请求连接,必须在回调中完成 st ={
"template_path": "template",#模板路径配置
"static_path":'static',
} #路由映射 匹配执行,否则404
application = tornado.web.Application([
("/main",MainHandler),
("/index",IndexHandler),
],**st) if __name__=="__main__":
application.listen() #io多路复用
tornado.ioloop.IOLoop.instance().start()

三:在tornado中使用异步IO请求模块

import tornado.ioloop
import tornado.web
import tornado.websocket
import time
from tornado.concurrent import Future
from tornado import httpclient
from tornado import gen
class MainHandler(tornado.web.RequestHandler):
def get(self): self.write("main") def post(self, *args, **kwargs):
pass class IndexHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
http = httpclient.AsyncHTTPClient()
yield http.fetch("http://www.google.com",self.done) def done(self):
self.write("index")
self.finish() def post(self, *args, **kwargs):
pass st ={
"template_path": "template",#模板路径配置
"static_path":'static',
} #路由映射 匹配执行,否则404
application = tornado.web.Application([
("/main",MainHandler),
("/index",IndexHandler),
],**st) if __name__=="__main__":
application.listen() #io多路复用
tornado.ioloop.IOLoop.instance().start()

四:请求间交互,使用future

import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado.concurrent import Future
from tornado import gen class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("main") class IndexHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
future = Future()
future.add_done_callback(self.done)
yield
future #由于future中的result中值一直未被赋值,所有客户端一直等待

def done(self,*args,**kwargs):
self.write("index")
self.finish() st ={
"template_path": "template",#模板路径配置
"static_path":'static',
} #路由映射 匹配执行,否则404
application = tornado.web.Application([
("/main",MainHandler),
("/index",IndexHandler),
],**st) if __name__=="__main__":
application.listen() #io多路复用
tornado.ioloop.IOLoop.instance().start()

我们可以在另一个请求中去为这个future中result赋值,使当前请求返回

import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado.concurrent import Future
from tornado import gen future = None class MainHandler(tornado.web.RequestHandler):
def get(self):
global future
future.set_result(None)  #为Future中result赋值

self.write("main") class IndexHandler(tornado.web.RequestHandler):
@gen.coroutine
def
get(self):
global future
future = Future()
future.add_done_callback(self.done)
yield
future #由于future中的result中值一直未被赋值,所有客户端一直等待 def done(self,*args,**kwargs):
self.write("index")
self.finish() st ={
"template_path": "template",#模板路径配置
"static_path":'static',
} #路由映射 匹配执行,否则404
application = tornado.web.Application([
("/main",MainHandler),
("/index",IndexHandler),
],**st) if __name__=="__main__":
application.listen() #io多路复用
tornado.ioloop.IOLoop.instance().start()

五:自定义web框架(同步)

# coding:utf8
# __author: Administrator
# date: //
# /usr/bin/env python
import socket
from select import select
import re class HttpResponse(object):
"""
封装响应信息
"""
def __init__(self, content=''):
self.content = content
''' '''
self.status = "HTTP/1.1 200 OK"
self.headers = {}
self.cookies = {} self.initResponseHeader() def changeStatus(self,status_code,status_desc):
self.status = "HTTP/1.1 %s %s"%(status_code,status_desc) def initResponseHeader(self):
self.headers['Content-Type']='text/html; charset=utf-8'
self.headers['X-Frame-Options']='SAMEORIGIN'
self.headers['X-UA-Compatible']='IE=10'
self.headers['Cache-Control']='private, max-age=10'
self.headers['Vary']='Accept-Encoding'
self.headers['Connection']='keep-alive' def response(self):
resp_content = None
header_list = [self.status,]
for item in self.headers.items():
header_list.append("%s: %s"%(item[],item[])) header_str = "\r\n".join(header_list)
resp_content = "\r\n\r\n".join([header_str,self.content])
return bytes(resp_content, encoding='utf-8') class HttpRequest:
def __init__(self,content):
"""content:用户传递的请求头信息,字节型"""
self.content = content
self.header_bytes = bytes()
self.body_bytes = bytes() self.header_str = ""
self.body_str = "" self.header_dict = {} self.method = ""
self.url = ""
self.protocol = "" self.initialize()
self.initialize_headers() def initialize(self):
data = self.content.split(b"\r\n\r\n",)
if len(data) == : #全是请求头
self.header_bytes = self.content
else: #含有请求头和请求体
self.header_bytes,self.body_bytes = data
self.header_str = str(self.header_bytes,encoding="utf-8")
self.body_str = str(self.body_bytes,encoding="utf-8") def initialize_headers(self):
headers = self.header_str.split("\r\n")
first_line = headers[].split(" ")
if len(first_line) == :
self.method,self.url,self.protocol = first_line
for line in headers[:]:
k_v = line.split(":",)
if len(k_v) == :
k,v = k_v
self.header_dict[k] = v def main(request):
return "main" def index(request):
return "index" routers = [
("/main/",main),
('/index/',index),
] def run():
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, )
sock.bind(('127.0.0.1', ))
sock.listen()
sock.setblocking(False) inputs = []
inputs.append(sock)
while True:
rlist, wlist, elist = select(inputs, [], [], 0.05) # http是单向的,我们只获取请求即可
for r in rlist:
if r == sock: # 有新的请求到来
conn, addr = sock.accept()
conn.setblocking(False)
inputs.append(conn)
else: # 客户端请求数据
data = b""
# 开始获取请求头
while True:
try:
chunk = r.recv()
data += chunk
except BlockingIOError as e:
chunk = None
if not chunk:
break # 处理请求头,请求体
request = HttpRequest(data)
#.获取url
#.路由匹配
#.执行函数,获取返回值
#.将返回值发送
flag = False
func = None
for route in routers:
if re.match(route[],request.url):
flag = True
func = route[]
break
if flag:
result = func(request)
response = HttpResponse(result)
r.sendall(response.response())
else:
response = HttpResponse("Not Found")
response.changeStatus(,"Not Page")
r.sendall(response.response())
inputs.remove(r)
r.close() if __name__ == "__main__":
run()

未实现异步非阻塞

六:完善自定义web框架(异步)

import socket
from select import select
import re,time class HttpResponse(object):
"""
封装响应信息
"""
def __init__(self, content=''):
self.content = content
''' '''
self.status = "HTTP/1.1 200 OK"
self.headers = {}
self.cookies = {} self.initResponseHeader() def changeStatus(self,status_code,status_desc):
self.status = "HTTP/1.1 %s %s"%(status_code,status_desc) def initResponseHeader(self):
self.headers['Content-Type']='text/html; charset=utf-8'
self.headers['X-Frame-Options']='SAMEORIGIN'
self.headers['X-UA-Compatible']='IE=10'
self.headers['Cache-Control']='private, max-age=10'
self.headers['Vary']='Accept-Encoding'
self.headers['Connection']='keep-alive' def response(self):
resp_content = None
header_list = [self.status,]
for item in self.headers.items():
header_list.append("%s: %s"%(item[],item[])) header_str = "\r\n".join(header_list)
resp_content = "\r\n\r\n".join([header_str,self.content])
return bytes(resp_content, encoding='utf-8') class HttpRequest:
def __init__(self,content):
"""content:用户传递的请求头信息,字节型"""
self.content = content
self.header_bytes = bytes()
self.body_bytes = bytes() self.header_str = ""
self.body_str = "" self.header_dict = {} self.method = ""
self.url = ""
self.protocol = "" self.initialize()
self.initialize_headers() def initialize(self):
data = self.content.split(b"\r\n\r\n",)
if len(data) == : #全是请求头
self.header_bytes = self.content
else: #含有请求头和请求体
self.header_bytes,self.body_bytes = data
self.header_str = str(self.header_bytes,encoding="utf-8")
self.body_str = str(self.body_bytes,encoding="utf-8") def initialize_headers(self):
headers = self.header_str.split("\r\n")
first_line = headers[].split(" ")
if len(first_line) == :
self.method,self.url,self.protocol = first_line
for line in headers[:]:
k_v = line.split(":",)
if len(k_v) == :
k,v = k_v
self.header_dict[k] = v class Future:
def __init__(self,timeout):
self.result = None
self.timeout = timeout
self.start = time.time() def add_callback_done(self,callback,request):
self.callback = callback
self.request = request def call(self):
if self.result == "timeout":  #超时就不要去获取页面数据,直接返回超时
return "timeout"
if self.result:  #若是没有超时,去获取回调数据
return self.callback(self.request) def callback(request):
print(request)
return "async main" f = None def main(request):
global f
f = Future(10)
f.add_callback_done(callback,request)  #设置回调
return
f def index(request):
return "index" def stop(request):
if f:
f.result = True
return "stop" routers = [
("/main/",main),
('/index/',index),
('/stop/', stop),  #用于向future的result赋值
] def run():
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, )
sock.bind(('127.0.0.1', ))
sock.listen()
sock.setblocking(False) inputs = []
async_request_dict = {}
inputs.append(sock)
while True:
rlist, wlist, elist = select(inputs, [], [], 0.05) # http是单向的,我们只获取请求即可
for r in rlist:
if r == sock: # 有新的请求到来
conn, addr = sock.accept()
conn.setblocking(False)
inputs.append(conn)
else: # 客户端请求数据
data = b""
# 开始获取请求头
while True:
try:
chunk = r.recv()
data += chunk
except BlockingIOError as e:
chunk = None
if not chunk:
break # 处理请求头,请求体
request = HttpRequest(data)
#.获取url
#.路由匹配
#.执行函数,获取返回值
#.将返回值发送
flag = False
func = None
for route in routers:
if re.match(route[],request.url):
flag = True
func = route[]
break
if flag:
result = func(request)
if isinstance(result,Future):  #对于future对象,我们另外做异步处理,不阻塞当前操作
async_request_dict[r] = result
continue

response = HttpResponse(result)
r.sendall(response.response())
else:
response = HttpResponse("Not Found")
response.changeStatus(,"Not Page")
r.sendall(response.response())
inputs.remove(r)
r.close() for conn in list(async_request_dict.keys()):  #另外对future对象处理
future = async_request_dict[conn]
start = future.start
timeout = future.timeout
if (start+timeout) <= time.time():  #超时检测
future.result = "timeout"
if future.result:
response = HttpResponse(future.call())  #获取回调数据
conn.sendall(response.response())
conn.close()
del async_request_dict[conn]  #删除字典中这个链接,和下面inputs列表中链接
inputs.remove(conn) if __name__ == "__main__":
run()

python---tornado补充(异步非阻塞)的更多相关文章

  1. Tornado的异步非阻塞

    阻塞和非阻塞Web框架 只有Tornado和Node.js是异步非阻塞的,其他所有的web框架都是阻塞式的. Tornado阻塞和非阻塞两种模式都支持. 阻塞式: 代表:Django.Flask.To ...

  2. tornado 之 异步非阻塞

    异步非阻塞 1.基本使用 装饰器 + Future 从而实现Tornado的异步非阻塞 import tornado.web import tornado.ioloop from tornado im ...

  3. Tornado之异步非阻塞

    同步模式:同步模式下,只有处理完前一个任务下一个才会执行 class MainHandler(tornado.web.RequestHandler): def get(self): time.slee ...

  4. Python web框架 Tornado(二)异步非阻塞

    异步非阻塞 阻塞式:(适用于所有框架,Django,Flask,Tornado,Bottle) 一个请求到来未处理完成,后续一直等待 解决方案:多线程,多进程 异步非阻塞(存在IO请求): Torna ...

  5. Python web框架 Tornado异步非阻塞

    Python web框架 Tornado异步非阻塞   异步非阻塞 阻塞式:(适用于所有框架,Django,Flask,Tornado,Bottle) 一个请求到来未处理完成,后续一直等待 解决方案: ...

  6. Tornado异步非阻塞的使用以及原理

    Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快.得利于其 非阻塞的方式和对 epoll 的运用,Tornado ...

  7. 03: 自定义异步非阻塞tornado框架

    目录:Tornado其他篇 01: tornado基础篇 02: tornado进阶篇 03: 自定义异步非阻塞tornado框架 04: 打开tornado源码剖析处理过程 目录: 1.1 源码 1 ...

  8. Tornado 异步非阻塞

    1 装饰器 + Future 从而实现Tornado的异步非阻塞 class AsyncHandler(tornado.web.RequestHandler): @gen.coroutine def ...

  9. 利用tornado使请求实现异步非阻塞

    基本IO模型 网上搜了很多关于同步异步,阻塞非阻塞的说法,理解还是不能很透彻,有必要买书看下. 参考:使用异步 I/O 大大提高应用程序的性能 怎样理解阻塞非阻塞与同步异步的区别? 同步和异步:主要关 ...

  10. 200行自定义异步非阻塞Web框架

    Python的Web框架中Tornado以异步非阻塞而闻名.本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow. 一.源码 本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞 ...

随机推荐

  1. Tempter of the Bone HDU 1010(DFS+剪枝)

    Problem Description The doggie found a bone in an ancient maze, which fascinated him a lot. However, ...

  2. 王者荣耀交流协会第一次scrum会议

    照片: 拍照的人是我(高远博),没有出镜.开会时间是17:00到17:37. 昨天的成绩: (1)优化了折线图界面 今天的计划: (1)小组成员汇报昨日成果. (2)小组成员继续推进任务. 遇到的困难 ...

  3. ubuntu16.04卸载火狐,Amazon

    一.卸载火狐: . dpkg --get-selections |grep firefox .sudo apt-get purge firefox unity-scope-firefoxbookmar ...

  4. lintocde-247-线段树的查询 II

    247-线段树的查询 II 对于一个数组,我们可以对其建立一棵 线段树, 每个结点存储一个额外的值 count 来代表这个结点所指代的数组区间内的元素个数. (数组中并不一定每个位置上都有元素) 实现 ...

  5. C#高级编程 (第六版) 学习 第六章:运算符和类型强制转换

    第六章 运算符和类型强制转换 1,运算符 类别 运算符 算术运算符 + - * / % 逻辑运算符 & | ^ ~ && || ! 字符串连接运算符 + 增量和减量运算符 ++ ...

  6. springmvc 路由

    工作中MVC是较常使用的web框架,作为研发人员,也习惯了以编写Controller作为项目开始,写好了Controller和对应的方法,加上@RequestMapping注解,我们也就认为一切已经准 ...

  7. MongoDb企业应用实战(一) 写在MongoDb应用介绍之前(i)

    故事背景: 本人有幸,经老友( 现为x知名快递公司技术总监 ) 推荐进入中国前三大民营快递公司之一工作,在此非常感谢他,在此也非常感谢我在第一家公司帮助我进步的兄弟(我在时的项目经理,现为 x  知名 ...

  8. 在Eclipse中开发WEB项目

    本文的演示是从本地文件创建dynamic web project,从svn检出的同时创建dynamic web project于此类似.我们推荐使用解压版的tomcat6.x版本,来作为服务器.可以到 ...

  9. LoadRunner脚本参数化常见错误

    错误代码:Error:missing newline in d:\loadrunner\username.dat 错误原因:场景设置不合理,参数数量不够,或者参数化文件有问题. 1)如果参数化文件反复 ...

  10. asp.net下使用Cookie保存登录信息

    在网页中登录窗口是最常见的,如果把登录信息存在客户机Cookie中,下次用户登录时,网页先在客户机上查找登录信息,如果成功即可跳过登录步骤直接到主窗口,如登录界面如下: