Tornado —— python web-server框架 和 web应用库框架

版权声明:本文为博主原创文章,转载请注明原文链接。 https://blog.csdn.net/Frank_Abagnale/article/details/80973767

初学笔记

Python Tornado web server 是一个用Python语言写成的Web服务器兼Web应用框架。
与web.py相同,tornado也是一种非常轻量的web框架,其具有异步非阻塞IO的处理方式。

1.安装

# pip 安装
$ sudo pip install tornado
# yum/apt安装
$ sudo yum install python-tornado
$ sudo apt install python-tornado

2.hello world
按照国际管理,先来一个入门的

## 主函数部分
if __name__ == "__main__":
  handlers = [(r"/cmd", CmdHander),
              (r"/cmd/(.*)", CmdHander),
              ]
  application = tornado.web.Application(handlers)
  ## 设置监听端口
  application.listen(7890) 
  ## 启动
  tornado.ioloop.IOLoop.instance().start()
## 实现子类和方法重载
#=============================================================================
# 下面的方式实现了两个简单的方法get/post,可以分别使用以下curl命令简单测试:
# curl -X GET http://127.0.0.1:7980/cmd/test
# curl -X POST http://127.0.0.1:7890/cmd/test --data aaa=123 --data BBB=112
# *(也可以用request / urllib2编写测试demo , 这里不再介绍。)
#=============================================================================
class CmdHander(tornado.web.RequestHandler):
  def get(self, name):
    #temp = self.request.uri.split('/')[-1]
    print "hander",name
    ## sleep
    time.sleep(10)
    ##  此处阻塞会阻塞整个服务,包括cmd hander和其他hander
    print "finish"
    self.set_header('Content-Type', 'application/json; charset=UTF-8')
    self.write(json.dumps({"result":"success"}))
    self.finish()
    return

  def post(self, *args, **kwargs):
    param = self.request.body.decode('utf-8')
    temp = self.request.uri.split('/')[-1]
    print "API:",temp
    print "parameter:",param
    if "=" in param :
      extend = dict(urlparse.parse_qsl(param))
    else :
      extend = json.loads(param, encoding='UTF-8', )
    ## sleep
    time.sleep(10)
    print "type of extend: ", type(extend)
    print "parameter extend:",extend
    self.set_header('Content-Type', 'application/json; charset=UTF-8')
    self.write(json.dumps({"result":"success"}))
    self.finish()
    return
    # ========================================================================
    # 同步(同时只处理一个请求)-阻塞(等待函数返回才能执行下面的操作)
    # 我们在上面代码中加入了sleep来模拟耗时操作,测试后我们发现:当同时多次发出请求,整个进程
    # 会因为耗时操作而阻塞,服务不能再接收和处理新的请求。效率很差。
    # ========================================================================

由于实时web功能需要为每个用户提供一个多数时间被闲置的长连接, 在传统的同步web服务器中,这意味着要为每个用户提供一个线程, 但是每个线程的开销都是很昂贵的.为了尽量减少并发连接造成的开销,Tornado使用了一种单线程事件循环的方式.基于上述问题,可以引用一些修饰方法和ThreadPoolExecutor方法,实现:异步-阻塞

3.异步-阻塞模式

from concurrent.futures import ThreadPoolExecutor
from tornado.concurrent import run_on_executor

class OrdHander(tornado.web.RequestHandler) :
  ## 设置线程池最大线程数
  executor = ThreadPoolExecutor(2)
  @tornado.web.asynchronous  # 将请求变成长连接
  @run_on_executor
  def get(self, *args, **kwargs):
    time.sleep(10)
    self.set_header('Content-Type', 'application/json; charset=UTF-8')
    self.write(json.dumps({"result":"success"}))
    self.finish()
    # ===================================================================
    # 异步(同时处理多请求)- 阻塞(等待函数返回才能执行下面的操作)
    # ===================================================================

基于上述方式,可以使用协程,耗时部分封装在函数中处理

class OrdHander(tornado.web.RequestHandler) :
  ## 最多同时并发处理的线程数
  executor = ThreadPoolExecutor(2)

  @tornado.web.asynchronous
  @tornado.gen.coroutine
  def get(self,*args, **kwargs):
    print "start get"
    #time.sleep(10)
    ## 将耗时操作通过并发协程处理,(虽然两个任务都耗时10秒,但是同时调用两次get,可以并发执行,总耗时还是10秒)
    response = yield self.my_sleep(10)
    print "response",response
    self.set_header('Content-Type', 'application/json; charset=UTF-8')
    self.write(json.dumps({"result": "success","response":response}))
    self.finish()

  @tornado.web.asynchronous   # 将请求变成长连接
  @tornado.gen.coroutine
  def post(self, *args, **kwargs):
    param = self.request.body.decode('utf-8')
    temp = self.request.uri.split('/')[-1]
    print "API:",temp
    print "parameter:",param
    if "=" in param :
      extend = dict(urlparse.parse_qsl(param))
    else :
      extend = json.loads(param, encoding='UTF-8', )
    print "type of extend: ", type(extend)
    print "parameter extend:",extend
    #time.sleep(10)
    ## 将耗时操作通过并发协程处理
    response = yield self.my_sleep(10)
    self.set_header('Content-Type', 'application/json; charset=UTF-8')
    self.write(json.dumps({"result":"success","response":response}))
    print "finish"
    self.finish()

  @run_on_executor
  def my_sleep(self,s=0):
    print "in my_sleep"
    time.sleep(s)
    return s

4. 异步非阻塞模式
如果既需要异步的并发,同时还需要调用端不等待耗时操作的返回,可以继续执行,可以尝试以下方法:
1)创建一个消息队列,当收到请求时,将请求和参数放入队列,然后调用finish()结束阻塞。
2)创建一个控制线程,轮询队列,当队列不为空时创建新线程实现业务。
3)如果需要返回结果,可以充当主动端发起curl请求,返回结果。

猜你喜欢

转载自blog.csdn.net/Frank_Abagnale/article/details/80973767