一、异步非阻塞框架介绍
1、介绍
支持异步非阻塞web框架:tornado , node js
2、定义对比
异步IO模块:我们作为客户端向服务端“并发”请求
异步非阻塞web框架:针对服务端,希望一个线程处理更多的请求
二、tornado异步非阻塞
【要点提炼】
使用装饰器@gen.coroutine
模拟等待,使用特殊的形式等待5秒,写法
future=Future() tornado.ioloop.IOLoop.current().add_timeout(time.time()+5,self.done) yield future
1、场景实例1
程序1,之前写法,同步阻塞(先访问main会进入等待,此时访问index也到等main处理完了才有返回)
import tornado.ioloop import tornado.web import time class MainHandler(tornado.web.RequestHandler): def get(self): time.sleep(10) self.write("main") class IndexHandler(tornado.web.RequestHandler): def get(self): self.write("index") application=tornado.web.Application([ (r"/main",MainHandler), (r"/index", IndexHandler),]) if __name__=="__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
程序2,此时要用到future,实现异步不阻塞
from tornado import gen from tornado.concurrent import Future class MainHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): future = Future() tornado.ioloop.IOLoop.current().add_timeout(time.time() + 5, self.done) yield future def done(self): self.write("Main") self.finish() class IndexHandler(tornado.web.RequestHandler): def get(self): self.write("index") application=tornado.web.Application([ (r"/main",MainHandler), (r"/index", IndexHandler),]) if __name__=="__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
2、场景实例2 (请求外部url时引起的阻塞)
【要点提炼】
通过tornado发请求,实现异步非阻塞
from tornado import httpclient http=httpclient.AsyncHTTPClient() yield http.fetch("http://www.google.com",self.done)
future的作用
1、挂起当前请求,线程可以处理其他请求
2、future设置值,当前挂起的请求返回
future.set_result(None)
程序3,同步阻塞场景
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): import requests ret=requests.get("http://www.google.com") self.write("main") class IndexHandler(tornado.web.RequestHandler): def get(self): self.write("index") application=tornado.web.Application([ (r"/main",MainHandler), (r"/index", IndexHandler),]) if __name__=="__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
程序4、异步非阻塞
import tornado.ioloop import tornado.web from tornado import gen class MainHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): from tornado import httpclient http=httpclient.AsyncHTTPClient() yield http.fetch("http://www.google.com",self.done) def done(self,*args,**kwargs): self.write("Main") self.finish() class IndexHandler(tornado.web.RequestHandler): def get(self): self.write("index") application=tornado.web.Application([ (r"/main",MainHandler), (r"/index", IndexHandler),]) if __name__=="__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
3、实例3,(自己设置future的值,将挂起的请求释放)
future=None class MainHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): global future future=Future() future.add_done_callback(self.done) yield future def done(self,*args,**kwargs): self.write("Main") self.finish() class IndexHandler(tornado.web.RequestHandler): def get(self): global future future.set_result(None) #设置值,将挂起的请求释放 self.write("index") application=tornado.web.Application([ (r"/main",MainHandler), (r"/index", IndexHandler),]) if __name__=="__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
三、自定义web框架
1、使用socket实现同步的web框架
示例:
import socket import select class HttpRequest(object): """ 用来封装用户请求信息 """ def __init__(self, content): self.content = content #用户发来的请求数据,请求头和请求体 self.header_bytes = bytes() self.header_dict = {} self.body_bytes = bytes() self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b header_flag = True @property def header_str(self): return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v def index(requet): return "index" def main(request): return 'main' routers=[('/index',index), ('/main',main), ] def run(): sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) sock.bind(('127.0.0.1',8002,)) sock.listen(128) inputs=[] inputs.append(sock) while True: rlist,wlist,elist=select.select(inputs,[],[],0.05) 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(1024) data=data+chunk except Exception as e: chunk=None if not chunk: break #dada进行处理:请求头和请求体 #1、请求头中获取url #2、去路由中匹配,获取指定的函数 #3、执行函数,获取返回值 #4、发送给客户端 request=HttpRequest(data) import re flag=False func=None for route in routers: if re.match(route[0],request.url): flag=True func=route[1] break if flag: result=func(request) r.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) r.sendall(bytes(result, 'utf8')) else: r.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) r.sendall(b'404') inputs.remove(r) r.close() if __name__=="__main__": run()
2、自定义web框架支持异步
【要点提炼】
编写实现future功能,如访问的main,不执行操作
》示例2
import socket import select class HttpRequest(object): """ 用来封装用户请求信息 """ def __init__(self, content): self.content = content #用户发来的请求数据,请求头和请求体 self.header_bytes = bytes() self.header_dict = {} self.body_bytes = bytes() self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b header_flag = True @property def header_str(self): return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v
class Future(object): def __init__(self): self.result=None F=None def stop(request): global F F.result=b'future-xxxxx' return 'stop' def index(requet): return "index" def main(request): global F F=Future() return F routers=[('/index',index), ('/main',main), ('/stop',stop), ] def run(): sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) sock.bind(('127.0.0.1',8002,)) sock.listen(128) inputs=[] inputs.append(sock) async_request_dict={} while True: rlist,wlist,elist=select.select(inputs,[],[],0.05) 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(1024) data=data+chunk except Exception as e: chunk=None if not chunk: break request=HttpRequest(data) import re flag=False func=None for route in routers: if re.match(route[0],request.url): flag=True func=route[1] break if flag: result=func(request) if isinstance(result,Future): async_request_dict[r]=result else: r.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) r.sendall(bytes(result,encoding='utf8')) inputs.remove(r) r.close() else: r.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) r.sendall(b'404') inputs.remove(r) r.close() for conn in list(async_request_dict.keys()): future=async_request_dict[conn] if future.result: conn.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) conn.sendall(future.result) conn.close() del async_request_dict[conn] inputs.remove(conn) if __name__=="__main__": run()
示例2是手动写的方法停止阻塞,可以实现利用超时时间自动停止
》示例3
import socket import select import time class HttpRequest(object): """ 用来封装用户请求信息 """ def __init__(self, content): self.content = content #用户发来的请求数据,请求头和请求体 self.header_bytes = bytes() self.header_dict = {} self.body_bytes = bytes() self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b header_flag = True @property def header_str(self): return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v class Future(object): def __init__(self,timeout=0): self.result=None self.timeout=timeout self.start=time.time() F=None def index(requet): return "index" def main(request): global F F=Future(5) return F routers=[('/index',index), ('/main',main), ] def run(): sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) sock.bind(('127.0.0.1',8002,)) sock.listen(128) inputs=[] inputs.append(sock) async_request_dict={} while True: rlist,wlist,elist=select.select(inputs,[],[],0.05) 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(1024) data=data+chunk except Exception as e: chunk=None if not chunk: break request=HttpRequest(data) import re flag=False func=None for route in routers: if re.match(route[0],request.url): flag=True func=route[1] break if flag: result=func(request) if isinstance(result,Future): async_request_dict[r]=result else: r.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) r.sendall(bytes(result,encoding='utf8')) inputs.remove(r) r.close() else: r.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) r.sendall(b'404') inputs.remove(r) r.close() for conn in list(async_request_dict.keys()): future=async_request_dict[conn] start=future.start timeout=future.timeout ctime=time.time() if (start+timeout)<=ctime: future.result=b'timeout' if future.result: conn.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", 'utf8')) conn.sendall(future.result) conn.close() del async_request_dict[conn] inputs.remove(conn) if __name__=="__main__": run()
标签:__,web,异步,python,self,bytes,tornado,main,def From: https://www.cnblogs.com/steven223-z/p/17775414.html