tornado异步非阻塞请求

2019-04-09  本文已影响0人  来一碗花甲粉

基础知识

首先对同步/异步、阻塞/非阻塞、以及tornado中asyncio进行了解,参考下面的文章
1.python中的异步实践与tornado应用
https://my.oschina.net/yangyanxing/blog/3001436
2.关于 asyncio
https://binglau7.github.io/2018/01/30/%E5%85%B3%E4%BA%8E-asyncio-%E7%9A%84%E5%96%83%E5%96%83%E8%87%AA%E8%AF%AD/

注意

程序中的数据库读取等io操作都要改为异步的,才能真正实现异步性能,否则还是会阻塞请求

实践

  1. 因为项目中历史问题,让前端统一接口调用方式,在新tornado后端服务中,采用了异步转发
    使用
    python3.7 中 async/await
    tornado 5.1 中 tornado.httpclient.AsyncHTTPClient()
    //tornado.gen.Task 方法在5.1版本以后弃用
from .base.base_handler import BaseHandler
import tornado.web
import tornado.gen
import tornado.httpclient
from tornado.options import options
import time
import asyncio

class RedirectHandler(BaseHandler):
   async def post(self):
       method = self.get_argument('method')
       modular = self.get_argument('modular')
       headers = self.request.headers
       body = self.request.body
       http_client = tornado.httpclient.AsyncHTTPClient()
       url = 'http://localhost:{0}/{1}/{2}'.format(options.port, modular, method)
       resp = await http_client.fetch(
           url,
           method="POST", 
           headers=headers,
           body=body, 
           validate_cert=False
       )
       #响应的headers
       #print(resp.headers)
       self._headers = resp.headers
       self.write(resp.body)
  1. 多线程使用
    项目中需要导出表格,比较耗时,使用异步多线程
    使用
    python3.7 中 ThreadPoolExecutor
    tornado 5.1 +
    @tornado.gen.coroutine
    @run_on_executor
import tornado.web
import tornado.gen
from tornado.ioloop import IOLoop
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor

from .base.base_handler import BaseHandler
from utils.json_encoder import convert2json, error2json
from constants import *
from service.export_deliver.dispatch_center import ExportDeliverDispatch
from utils.time_convert import timestamp_to_datetime

class ExportDeliverHandler(BaseHandler):
    executor = ThreadPoolExecutor(10) #  线程池

    #@tornado.web.asynchronous
    @tornado.gen.coroutine
    def post(self):
        params = self.request.body
        params = json.loads(params)
        temp_id = params.get('tempId', '')
        dataset_col = params.get('dataset').get('colName')

        filename, stream = yield self.deliver(params)
        #Content-Type这里我写的时候是固定的了,也可以根据实际情况传值进来
        self.set_header('Content-Type', 'application/octet-stream')
        # 中文文件名用quote解决
        self.set_header('Content-Disposition', "attachment; filename={0}".format(quote(filename)))
        #读取的模式需要根据实际情况进行修改
        self.write(stream)

    @run_on_executor
    def deliver(self, params):
       # dosomething
        return filename, stream

可用遇到报错信息:
RuntimeError: There is no current event loop in thread ThreadPoolExecutor-xxx
解决:
线程中执行代码的开始,加上下面代码(在2.关于 asyncio中也有介绍)

new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
上一篇下一篇

猜你喜欢

热点阅读