• 自定义异步非阻塞框架


    tornado的异步非阻塞

    tornado支持同步和异步两种模式,一般的写法是同步方式,想要支持异步就需要一点特殊的写法。
    web框架的异步模式是为了让程序的效率更高,如果http请求让线程干的事情都是计算密集型任务,那么单个线程无论怎么做都不可能提高效率,但是如果任务是不消耗CPU但是需要耗时的任务,那么一个非阻塞+IO多路复用+一个线程能帮我们提升效率。
    在tornado中的的编程中,非计算型任务一般可以分为三种:1. 在视图里主动 sleep(当然一般不会这么傻,无缘无故就sleep,测试环境可能需要用到) 2. 在这个视图中又往别的地方发http请求,这时可以利用等待的这段时间去做点别的事 3. 返回一个future对象,暂停住请求
    等future对象的_result属性被赋值再返回请求所需要的响应

    主动sleep

    import tornado.web
    import tornado.ioloop
    from tornado import gen
    import time
    from tornado.concurrent import Future
    
    class MainHandler(tornado.web.RequestHandler):
        @gen.coroutine
        def get(self, *args, **kwargs):
            future = Future()
            tornado.ioloop.IOLoop.current().add_timeout(time.time() + 5, self.done)
            yield future
    
        def done(self):
            self.write('hahah')
            self.finish()
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self, *args, **kwargs):
            self.write('index')
    
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
    }
    
    application = tornado.web.Application([
        (r"/main", MainHandler),
        (r"/index", IndexHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8009)
        tornado.ioloop.IOLoop.instance().start()
    

    发http请求

    import tornado.web
    import tornado.ioloop
    from tornado import gen
    from tornado import httpclient
    
    
    class MainHandler(tornado.web.RequestHandler):
        @gen.coroutine
        def get(self):
            http = httpclient.AsyncHTTPClient()
            yield http.fetch("http://www.google.com", self.done)
    
        def done(self, response):
            self.finish('main')
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self, *args, **kwargs):
            self.write('index')
    
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
    }
    
    application = tornado.web.Application([
        (r"/main", MainHandler),
        (r"/index", IndexHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8009)
        tornado.ioloop.IOLoop.instance().start()
    

    返回单纯的future等待被_result赋值

    import tornado.web
    import tornado.ioloop
    from tornado import gen
    from tornado.concurrent import Future
    
    future = ''
    
    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):
            print(args, kwargs)
            self.write('Main')
            self.finish()
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self, *args, **kwargs):
            global future
            future.set_result('xx')
            self.write('index')
    
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
    }
    
    application = tornado.web.Application([
        (r"/main", MainHandler),
        (r"/index", IndexHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8009)
        tornado.ioloop.IOLoop.instance().start()
    

    自定义web框架

    import socket
    import select
    import time
    
    class HttpRequest(object):
        """
        用户封装用户请求信息
        """
        def __init__(self, content):
            """
    
            :param content:用户发送的请求数据:请求头和请求体
            """
            self.content = content
    
            self.header_bytes = bytes()
            self.body_bytes = bytes()
    
            self.header_dict = {}
    
            self.method = ""
            self.url = ""
            self.protocol = ""
    
            self.initialize()
            self.initialize_headers()
    
        def initialize(self):
    
            temp = self.content.split(b'
    
    ', 1)
            if len(temp) == 1:
                self.header_bytes += temp
            else:
                h, b = temp
                self.header_bytes += h
                self.body_bytes += b
    
        @property
        def header_str(self):
            return str(self.header_bytes, encoding='utf-8')
    
        def initialize_headers(self):
            headers = self.header_str.split('
    ')
            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()
    
    def main(request):
        f = Future(5)
        return f
    
    def index(request):
        return "index"
    
    routers = [
        ('/main',main),
        ('/index',index),
    ]
    
    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", 9999,))
        sock.setblocking(False)
        sock.listen(5)
    
        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
                    # data进行处理:请求头和请求体
                    request = HttpRequest(data)
                    # 1. 请求头中获取url
                    # 2. 去路由中匹配,获取指定的函数
                    # 3. 执行函数,获取返回值
                    # 4. 将返回值 r.sendall(b'xx')
                    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(result,encoding='utf-8'))
                            inputs.remove(r)
                            r.close()
                    else:
                        r.sendall(b"404")
                        inputs.remove(r)
                        r.close()
            del_con_list = []
            for conn in 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(future.result)
                    conn.close()
                    del_con_list.append(conn)
                    inputs.remove(conn)
            for conn in del_con_list:
                async_request_dict.pop(conn)
    if __name__ == '__main__':
        run()
    
  • 相关阅读:
    Asp.Net服务器控件开发的Grid实现(四)回发事件
    Win8的IIS中架设php
    jsonp其实很简单【ajax跨域请求】
    Asp.Net服务器控件开发的Grid实现(三)列编辑器
    Asp.Net服务器控件开发的Grid实现(二)Html标记渲染
    构建之法阅读笔记01
    四则运算2
    psp0
    随机生成30道四则运算
    学习进度条
  • 原文地址:https://www.cnblogs.com/longyunfeigu/p/9505282.html
Copyright © 2020-2023  润新知