Tornado---异步非阻塞(3)

import tornado.ioloop
import tornado.web
from tornado.options import define, options
import os.path,time,requests

define("ip", default="162.247.101.143", help="run on the given port", type=str)
define("port", default=8003, help="run on the given port", type=int)

class WelcomeHandler(tornado.web.RequestHandler):
    def get(self):
        time.sleep(8)
        response = requests.get("http://www.baidu.com", timeout=8)
        response = response.text
        return self.write(response)

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("### welcome !!! ###")

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r'/', WelcomeHandler),
            (r'/login', LoginHandler),
        ]
        settings = dict(
            cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            xsrf_cookies=True,
        )
        tornado.web.Application.__init__(self, handlers, **settings)

if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = Application()
    app.listen(options.port)
    print("visit at", "http://127.0.0.1:%s" % options.port)
    tornado.ioloop.IOLoop.instance().start()

假如你使用页面请求先访问http://localhost:8003/,再访问http://localhost:8003/login。你会发现本来可以立刻返回的/login的请求会一直阻塞到/请求完才返回。这是为啥?为啥我的请求被/请求阻塞了。
这是时候你有没有想起@tornado.web.asynchronous这个装饰器?但是使用这个装饰器有个前提就是你要耗时的执行需要执行异步,比如上面的time.sleep,你只是加装饰器是没有作用的,而且需要注意的是 Tornado默认在函数处理返回时关闭客户端的连接,但是当你使用@tornado.web.asynchonous装饰器时,Tornado永远不会自己关闭连接,需要显式的self.finish()关闭。
解决方案如下: 

解决方案一:

# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from tornado.options import define, options
import os.path,time,requests
from tornado.concurrent import run_on_executor
# 这个并发库在python3自带在python2需要安装sudo pip install futures
from concurrent.futures import ThreadPoolExecutor # (它是由thread模块封装的(创建线程的模块))

define("ip", default="162.247.101.143", help="run on the given port", type=str)
define("port", default=8003, help="run on the given port", type=int)

class WelcomeHandler(tornado.web.RequestHandler):
    # 通过协程实现异步  yield 调用函数 @run_on_executor装饰函数(函数不用yield)。需要下载requests 和futures。
    # 当发生阻塞时,能够创建一个新的线程来执行阻塞的任务(多线程)。executor = ThreadPoolExecutor(2)。
    executor = ThreadPoolExecutor()
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self):
        status = int(self.get_argument("status", 0))
        # 这个response就是fun()函数的返回值。程序会卡在这里等待返回值,但不影响其他url的访问。
        response = yield self.fun(status)
        print "response===>"      # 不会打印,直到fun()函数执行完成,返回结果才继续向下执行。
        self.write(response)
        self.finish()

    @run_on_executor
    def fun(self, status):
        # 在这个函数里执行耗时任务,比如:time.sleep(16)。或者爬取十万条网站数据。或者response = requests.get('http://127.0.0.1:8003/synic')等。
        time.sleep(6)
        # response = requests.get("http://127.0.0.1:8003/synic")
        response = requests.get("http://www.taobao.com", timeout=8)
        return response.text

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("### welcome login!!! ###")

# class SyncHandler(tornado.web.RequestHandler):
#     def get(self):
#         time.sleep(10)
#         self.write('AHandler Request')

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r'/', WelcomeHandler),
            (r'/login', LoginHandler),
            # (r"/synic", SyncHandler),
        ]
        settings = dict(
            cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            xsrf_cookies=True,
        )
        tornado.web.Application.__init__(self, handlers, **settings)

if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = Application()
    app.listen(options.port)
    print("visit at", "http://127.0.0.1:%s" % options.port)
    tornado.ioloop.IOLoop.instance().start()
# 这种异步方式对get/post请求都有效果,都能转化成异步处理。对ajax的post请求也有效果。
# 上面的示例仅仅展示了get请求。

解决方案二:

https://www.cnblogs.com/liujianzuo888/articles/6255824.html 

https://www.jb51.net/article/87459.htm

https://blog.csdn.net/joeyon1985/article/details/41956027

https://www.cnblogs.com/b02330224/p/10203414.html 

https://blog.csdn.net/qq_23282479/article/details/80424946

https://www.jianshu.com/p/31fae7dd05ba

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值