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