zoukankan      html  css  js  c++  java
  • 关于Python Web框架——Tornado

    关于Tornado的入门看这篇文章,写的非常好:

    https://zhuanlan.zhihu.com/p/37382503

    Tornado 是一个Python web框架和异步网络库,使用非阻塞网络I/O。

    Tornado可以被分为4个主要的部分:

    • web框架
    • HTTP的客户端和服务端实现
    • 异步网络库
    • 协程库

    WSGI是Web Server Gateway Interface的缩写。

    实时web功能需要为每个用户提供一个多数时间被闲置的长连接, 在传统的同步web服务器中,这意味着要为每个用户提供一个线程, 当然每个线程的开销都是很昂贵的.

    为了尽量减少并发连接造成的开销,Tornado使用了一种单线程事件循环的方式. 这就意味着所有的应用代码都应该是异步非阻塞的, 因为在同一时间只有一个操作是有效的.

    知乎和掌阅的后端应该采用了这个框架。

    下面提供快速帮助回忆的代码:(阶乘服务和圆周率计算服务)

    # pi.py
    import json
    import math
    import redis
    import tornado.ioloop
    import tornado.web
    
    class FactorialService(object):
    
        def __init__(self, cache):
            self.cache = cache
            self.key = "factorials"
    
        def calc(self, n):
            s = self.cache.hget(self.key, str(n))
            if s:
                return int(s), True
            s = 1
            for i in range(1, n):
                s *= i
            self.cache.hset(self.key, str(n), str(s))
            return s, False
    
    class PiService(object):
    
        def __init__(self, cache):
            self.cache = cache
            self.key = "pis"
    
        def calc(self, n):
            s = self.cache.hget(self.key, str(n))
            if s:
                return float(s), True
            s = 0.0
            for i in range(n):
                s += 1.0/(2*i+1)/(2*i+1)
            s = math.sqrt(s*8)
            self.cache.hset(self.key, str(n), str(s))
            return s, False
    
    class FactorialHandler(tornado.web.RequestHandler):
    
        def initialize(self, factorial):
            self.factorial = factorial
    
        def get(self):
            n = int(self.get_argument("n") or 1)
            fact, cached = self.factorial.calc(n)
            result = {
                "n": n,
                "fact": fact,
                "cached": cached
            }
            self.set_header("Content-Type", "application/json; charset=UTF-8")
            self.write(json.dumps(result))
    
    class PiHandler(tornado.web.RequestHandler):
    
        def initialize(self, pi):
            self.pi = pi
    
        def get(self):
            n = int(self.get_argument("n") or 1)
            pi, cached = self.pi.calc(n)
            result = {
                "n": n,
                "pi": pi,
                "cached": cached
            }
            self.set_header("Content-Type", "application/json; charset=UTF-8")
            self.write(json.dumps(result))
    
    def make_app():
        cache = redis.StrictRedis("localhost", 6379)
        factorial = FactorialService(cache)
        pi = PiService(cache)
        return tornado.web.Application([
            (r"/fact", FactorialHandler, {"factorial": factorial}),
            (r"/pi", PiHandler, {"pi": pi}),
        ])
    
    if __name__ == "__main__":
        app = make_app()
        app.listen(8888)
        tornado.ioloop.IOLoop.current().start()

    因为两个Handler都需要用到redis,所以我们将redis单独抽出来,通过参数传递进去。另外Handler可以通过initialize函数传递参数,在注册路由的时候提供一个字典就可以传递任意参数了,字典的key要和参数名称对应。我们运行python pi.py,打开浏览器访问http://localhost:8888/pi?n=200,可以看到浏览器输出{"cached": false, "pi": 3.1412743276, "n": 1000},这个值已经非常接近圆周率了。

    下面来自知乎:(写的非常好)

    https://zhuanlan.zhihu.com/p/37382503

    Tornado:Hello, World

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.write("Hello, world")
    
    def make_app():
        return tornado.web.Application([
            (r"/", MainHandler),
        ])
    
    if __name__ == "__main__":
        app = make_app()
        app.listen(8888)
        tornado.ioloop.IOLoop.current().start()

    这是官方提供了Hello, World实例,执行python hello.py,打开浏览器访问http://localhost:8888/就可以看到服务器的正常输出Hello, world

    一个普通的tornado web服务器通常由四大组件组成。

    1. ioloop实例,它是全局的tornado事件循环,是服务器的引擎核心,示例中tornado.ioloop.IOLoop.current()就是默认的tornado ioloop实例。
    2. app实例,它代表着一个完成的后端app,它会挂接一个服务端套接字端口对外提供服务。一个ioloop实例里面可以有多个app实例,示例中只有1个,实际上可以允许多个,不过一般几乎不会使用多个。
    3. handler类,它代表着业务逻辑,我们进行服务端开发时就是编写一堆一堆的handler用来服务客户端请求。
    4. 路由表,它将指定的url规则和handler挂接起来,形成一个路由映射表。当请求到来时,根据请求的访问url查询路由映射表来找到相应的业务handler。

    这四大组件的关系是,一个ioloop包含多个app(管理多个服务端口),一个app包含一个路由表,一个路由表包含多个handler。ioloop是服务的引擎核心,它是发动机,负责接收和响应客户端请求,负责驱动业务handler的运行,负责服务器内部定时任务的执行

    当一个请求到来时,ioloop读取这个请求解包成一个http请求对象,找到该套接字上对应app的路由表,通过请求对象的url查询路由表中挂接的handler,然后执行handler。handler方法执行后一般会返回一个对象,ioloop负责将对象包装成http响应对象序列化发送给客户端。

    同一个ioloop实例运行在一个单线程环境下。

    关于ioloop:

    tornado.ioloop — Main event loop
    An I/O event loop for non-blocking sockets.(非阻塞套接字接口)
    IOLoop is a wrapper around the asyncio event loop. (异步事件循环)

    参考:

    https://tornado-zh.readthedocs.io/zh/latest/guide/async.html

    https://zhuanlan.zhihu.com/p/37382503

    https://www.tornadoweb.org/en/stable/ioloop.html

  • 相关阅读:
    Web网页数据抽取软件的设计与实现
    以Groovy的方式更稳定地解析HTML(转载)
    HTML 资讯汲取(上篇) 使用 JDOM 、 TagSoup 及 XPath
    html解析
    HTML 資訊汲取(下篇) TagSoup 輸出 namespace 問題的解決方案
    国外免费主机空间
    ASP.NET获取客户端IP地址、系统版本、浏览器版本
    阁下莫非就是当年华山论剑武功独步天下罕有其匹号称一朵梨花压海棠的少林寺智障大师收养的小沙弥低能的爱犬旺财踩扁的蟑螂小强曾滚过的一个粪球?
    html中table里的col标签
    Visual Studio 2010 中的 TODO
  • 原文地址:https://www.cnblogs.com/Flash-ylf/p/11618578.html
Copyright © 2011-2022 走看看