python---tornado补充(异步非阻塞)

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

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(10)
        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(8080)

    #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(8080)

    #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(8080)

    #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(8080)

    #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(8080)

    #io多路复用
    tornado.ioloop.IOLoop.instance().start()

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

# coding:utf8
# __author:  Administrator
# date:      2018/6/30 0030
# /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[0],item[1]))

        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",1)
        if len(data) == 1:  #全是请求头
            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[0].split(" ")
        if len(first_line) == 3:
            self.method,self.url,self.protocol = first_line
        for line in headers[1:]:
            k_v = line.split(":",1)
            if len(k_v) == 2:
                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, 1)
    sock.bind(('127.0.0.1', 8080))
    sock.listen(128)
    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(1024)
                        data += chunk
                    except BlockingIOError as e:
                        chunk = None
                    if not chunk:
                        break

                # 处理请求头,请求体
                request = HttpRequest(data)
                #1.获取url
                #2.路由匹配
                #3.执行函数,获取返回值
                #4.将返回值发送
                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)
                    response = HttpResponse(result)
                    r.sendall(response.response())
                else:
                    response = HttpResponse("Not Found")
                    response.changeStatus(404,"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[0],item[1]))

        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",1)
        if len(data) == 1:  #全是请求头
            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[0].split(" ")
        if len(first_line) == 3:
            self.method,self.url,self.protocol = first_line
        for line in headers[1:]:
            k_v = line.split(":",1)
            if len(k_v) == 2:
                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, 1)
    sock.bind(('127.0.0.1', 8080))
    sock.listen(128)
    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(1024)
                        data += chunk
                    except BlockingIOError as e:
                        chunk = None
                    if not chunk:
                        break

                # 处理请求头,请求体
                request = HttpRequest(data)
                #1.获取url
                #2.路由匹配
                #3.执行函数,获取返回值
                #4.将返回值发送
                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):  #对于future对象,我们另外做异步处理,不阻塞当前操作
                        async_request_dict[r] = result
                        continue
                    response = HttpResponse(result)
                    r.sendall(response.response())
                else:
                    response = HttpResponse("Not Found")
                    response.changeStatus(404,"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()

 

 

 

 

转载于:https://www.cnblogs.com/ssyfj/p/9246153.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中常用的Web框架有Flask、Tornado和Django。Flask是一个轻量级的Web框架,类似于Web.py,具有异步非阻塞IO的处理方式。 TornadoPython界中非常出名的一款Web框架,也属于轻量级的框架,被广泛用于构建高性能的异步Web应用。 Django是一个开源的Web应用框架,由Python写成,支持多种数据库引擎,可以让Web开发变得迅速且可扩展,不断更新以适应Python的最新版本。如果是新手程序员,可以从Django框架入手学习。 这三个框架都有自己的特点和适用场景,开发者可以根据项目需求和个人喜好选择适合自己的框架。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [目前最受欢迎的12个Python web框架,你用过几个?](https://blog.csdn.net/cky8792/article/details/100208770)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Python web框架之tornado(龙卷风)](https://blog.csdn.net/inthat/article/details/123362081)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值