Tornado----自定义异步非阻塞Web框架:Snow

Python的Web框架中Tornado以异步非阻塞而闻名。本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow。

一、源码

本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞的Web框架,其中便是众多异步非阻塞Web框架内部原理。

  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 import re
  4 import socket
  5 import select
  6 import time
  7
  8
  9 class HttpResponse(object):
 10     """
 11     封装响应信息
 12     """
 13     def __init__(self, content=‘‘):
 14         self.content = content
 15
 16         self.headers = {}
 17         self.cookies = {}
 18
 19     def response(self):
 20         return bytes(self.content, encoding=‘utf-8‘)
 21
 22
 23 class HttpNotFound(HttpResponse):
 24     """
 25     404时的错误提示
 26     """
 27     def __init__(self):
 28         super(HttpNotFound, self).__init__(‘404 Not Found‘)
 29
 30
 31 class HttpRequest(object):
 32     """
 33     用户封装用户请求信息
 34     """
 35     def __init__(self, conn):
 36         self.conn = conn
 37
 38         self.header_bytes = bytes()
 39         self.header_dict = {}
 40         self.body_bytes = bytes()
 41
 42         self.method = ""
 43         self.url = ""
 44         self.protocol = ""
 45
 46         self.initialize()
 47         self.initialize_headers()
 48
 49     def initialize(self):
 50
 51         header_flag = False
 52         while True:
 53             try:
 54                 received = self.conn.recv(8096)
 55             except Exception as e:
 56                 received = None
 57             if not received:
 58                 break
 59             if header_flag:
 60                 self.body_bytes += received
 61                 continue
 62             temp = received.split(b‘\r\n\r\n‘, 1)
 63             if len(temp) == 1:
 64                 self.header_bytes += temp
 65             else:
 66                 h, b = temp
 67                 self.header_bytes += h
 68                 self.body_bytes += b
 69                 header_flag = True
 70
 71     @property
 72     def header_str(self):
 73         return str(self.header_bytes, encoding=‘utf-8‘)
 74
 75     def initialize_headers(self):
 76         headers = self.header_str.split(‘\r\n‘)
 77         first_line = headers[0].split(‘ ‘)
 78         if len(first_line) == 3:
 79             self.method, self.url, self.protocol = headers[0].split(‘ ‘)
 80             for line in headers:
 81                 kv = line.split(‘:‘)
 82                 if len(kv) == 2:
 83                     k, v = kv
 84                     self.header_dict[k] = v
 85
 86
 87 class Future(object):
 88     """
 89     异步非阻塞模式时封装回调函数以及是否准备就绪
 90     """
 91     def __init__(self, callback):
 92         self.callback = callback
 93         self._ready = False
 94         self.value = None
 95
 96     def set_result(self, value=None):
 97         self.value = value
 98         self._ready = True
 99
100     @property
101     def ready(self):
102         return self._ready
103
104
105 class TimeoutFuture(Future):
106     """
107     异步非阻塞超时
108     """
109     def __init__(self, timeout):
110         super(TimeoutFuture, self).__init__(callback=None)
111         self.timeout = timeout
112         self.start_time = time.time()
113
114     @property
115     def ready(self):
116         current_time = time.time()
117         if current_time > self.start_time + self.timeout:
118             self._ready = True
119         return self._ready
120
121
122 class Snow(object):
123     """
124     微型Web框架类
125     """
126     def __init__(self, routes):
127         self.routes = routes
128         self.inputs = set()
129         self.request = None
130         self.async_request_handler = {}
131
132     def run(self, host=‘localhost‘, port=9999):
133         """
134         事件循环
135         :param host:
136         :param port:
137         :return:
138         """
139         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
140         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
141         sock.bind((host, port,))
142         sock.setblocking(False)
143         sock.listen(128)
144         sock.setblocking(0)
145         self.inputs.add(sock)
146         try:
147             while True:
148                 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs,0.005)
149                 for conn in readable_list:
150                     if sock == conn:
151                         client, address = conn.accept()
152                         client.setblocking(False)
153                         self.inputs.add(client)
154                     else:
155                         gen = self.process(conn)
156                         if isinstance(gen, HttpResponse):
157                             conn.sendall(gen.response())
158                             self.inputs.remove(conn)
159                             conn.close()
160                         else:
161                             yielded = next(gen)
162                             self.async_request_handler[conn] = yielded
163                 self.polling_callback()
164
165         except Exception as e:
166             pass
167         finally:
168             sock.close()
169
170     def polling_callback(self):
171         """
172         遍历触发异步非阻塞的回调函数
173         :return:
174         """
175         for conn in list(self.async_request_handler.keys()):
176             yielded = self.async_request_handler[conn]
177             if not yielded.ready:
178                 continue
179             if yielded.callback:
180                 ret = yielded.callback(self.request, yielded)
181                 conn.sendall(ret.response())
182             self.inputs.remove(conn)
183             del self.async_request_handler[conn]
184             conn.close()
185
186     def process(self, conn):
187         """
188         处理路由系统以及执行函数
189         :param conn:
190         :return:
191         """
192         self.request = HttpRequest(conn)
193         func = None
194         for route in self.routes:
195             if re.match(route[0], self.request.url):
196                 func = route[1]
197                 break
198         if not func:
199             return HttpNotFound()
200         else:
201             return func(self.request)

snow.py

二、使用

1. 基本使用

 1 from snow import Snow
 2 from snow import HttpResponse
 3
 4
 5 def index(request):
 6     return HttpResponse(‘OK‘)
 7
 8
 9 routes = [
10     (r‘/index/‘, index),
11 ]
12
13 app = Snow(routes)
14 app.run(port=8012)

2.异步非阻塞:超时

 1 from snow import Snow
 2 from snow import HttpResponse
 3 from snow import TimeoutFuture
 4
 5 request_list = []
 6
 7
 8 def async(request):
 9     obj = TimeoutFuture(5)
10     yield obj
11
12
13 def home(request):
14     return HttpResponse(‘home‘)
15
16
17 routes = [
18     (r‘/home/‘, home),
19     (r‘/async/‘, async),
20 ]
21
22 app = Snow(routes)
23 app.run(port=8012)

3.异步非阻塞:等待

基于等待模式可以完成自定制操作

 1 from snow import Snow
 2 from snow import HttpResponse
 3 from snow import Future
 4
 5 request_list = []
 6
 7
 8 def callback(request, future):
 9     return HttpResponse(future.value)
10
11
12 def req(request):
13     obj = Future(callback=callback)
14     request_list.append(obj)
15     yield obj
16
17
18 def stop(request):
19     obj = request_list[0]
20     del request_list[0]
21     obj.set_result(‘done‘)
22     return HttpResponse(‘stop‘)
23
24
25 routes = [
26     (r‘/req/‘, req),
27     (r‘/stop/‘, stop),
28 ]
29
30 app = Snow(routes)
31 app.run(port=8012)
时间: 2024-07-28 15:57:42

Tornado----自定义异步非阻塞Web框架:Snow的相关文章

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

Python的Web框架中Tornado以异步非阻塞而闻名.本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow. 一.源码 本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞的Web框架,其中便是众多异步非阻塞Web框架内部原理. #!/usr/bin/env python # -*- coding:utf-8 -*- import re import socket import select import time class HttpResponse(object)

Tornado的异步非阻塞

阻塞和非阻塞Web框架 只有Tornado和Node.js是异步非阻塞的,其他所有的web框架都是阻塞式的. Tornado阻塞和非阻塞两种模式都支持. 阻塞式: 代表:Django.Flask.Tornado.Bottle 一个请求到来未处理完成,后续请求则一直等待. 解决方案:多线程或多进程. 异步非阻塞(存在IO请求): 代表:Tornado(默认单进程/单线程) Tornado的阻塞模式示例 from tornado import ioloop from tornado.web impo

python-自定义异步非阻塞爬虫框架

api import socket import select class MySock: def __init__(self, sock, data): self.sock = sock self.data = data def __getattr__(self, item): return getattr(self.sock, item) class YinBing: def __init__(self): self.r_list = [] self.w_list = [] def add(

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

Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快.得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架. 一.Tornado的两种模式使用 1.同步阻塞模式 由于doing中sleep10秒,此时其他连接将被阻塞,必须等这次请求完成后其他请求才能连接成功. 1 import tornado.io

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

基本IO模型 网上搜了很多关于同步异步,阻塞非阻塞的说法,理解还是不能很透彻,有必要买书看下. 参考:使用异步 I/O 大大提高应用程序的性能 怎样理解阻塞非阻塞与同步异步的区别? 同步和异步:主要关注消息通信机制(重点在B?). 同步:A调用B,B处理直到获得结果,才返回给A. 异步:A调用B,B直接返回.无需等待结果,B通过状态,通知等来通知A或回调函数来处理. 阻塞和非阻塞:主要关注程序等待(重点在A?). 阻塞:A调用B,A被挂起直到B返回结果给A,A继续执行. 非阻塞:A调用B,A不会

异步非阻塞IO的Python Web框架--Tornado

Tornado的全称是Torado Web Server,从名字上就可知它可用作Web服务器,但同时它也是一个Python Web的开发框架.最初是在FriendFeed公司的网站上使用,FaceBook收购之后便进行了开源. 作为Web框架,是一个轻量级的Web框架,类似于另一个Python web 框架Web.py,其拥有异步非阻塞IO的处理方式. 作为Web服务器,Tornado有较为出色的抗负载能力,官方用nginx反向代理的方式部署Tornado和其它Python web应用框架进行对

初始Tornado异步非阻塞

Tornado  异步非阻塞 from tornado import gen class MainHandler(tornado.web.RequestHandler): @gen.coroutine  #关键点 def get(self): futrue =Future()#关键点 #阻塞内容,必须写这个格式,time.sleep不好使 #tornado.ioloop.IOLoop.current().add_timeout(time.time()+10,self.doing) #关键点 se

使用tornado让你的请求异步非阻塞

http://www.dongwm.com/archives/shi-yong-tornadorang-ni-de-qing-qiu-yi-bu-fei-zu-sai/?utm_source=tuicool&utm_medium=referral 前言 也许有同学很迷惑:tornado不是标榜异步非阻塞解决10K问题的嘛?但是我却发现不是torando不好,而是你用错了.比如最近发现一个事情:某网站打开页面很慢,服务器cpu/内存都正常.网络状态也良好. 后来发现,打开页面会有很多请求后端数据库

爬虫必备—性能相关(异步非阻塞)

在编写爬虫时,性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待,从而使得请求整体变慢. 1. 同步执行 1 import requests 2 3 def fetch_async(url): 4 response = requests.get(url) 5 return response 6 7 8 url_list = ['http://www.github.com', 'http://www.bing.com'] 9 10 for url in url_list: