tornado 异步得到结果后write报错Cannot write() after finish()

目录

 

一.问题引入

二.代码

三.解决

四.后续

五.拓展:


一.问题引入

tornado 是一个很好的异步非阻塞Python框架,有着优秀的大并发处理能力,使用中出现如下错误:

raise RuntimeError("Cannot write() after finish()")

二.代码

以下是涉及的代码:

thread_pool = ThreadPoolExecutor(2)
def go():
    all = selected_customer_all()
    return all
class R_SelectionCustomer(MyBackStargeRequestHandler):
    @authenticated  # 需要身份认证才能访问的处理器
    #让一个请求一直保持 连接状态,而不是马上返回,直到一个主处理行为返回。
    @gen.coroutine
    def get(self):
        print("我R_SelectionCustomer被访问了")
        #self.get_argument()
        all = yield thread_pool.submit(go)
        self.write(str(RJ(data=all,total=len(all))))
       

三.解决

查阅资料:

        当一个处理请求的行为被执行之后,这个请求会自动地结束。因为 Tornado 当中使用了 一种非阻塞式的 I/O 模型,所以你可以改变这种默认的处理行为——让一个请求一直保持 连接状态,而不是马上返回,直到一个主处理行为返回。要实现这种处理方式,只需要 使用 tornado.web.asynchronous 装饰器就可以了。

使用了这个装饰器之后,你必须调用 self.finish() 已完成 HTTTP 请求,否则 用户的浏览器会一直处于等待服务器响应的状态。

所有需要在

@gen.coroutine上面加上@tornado.web.asynchronous,并且最后调用 self.finish()表示已完成 HTTTP 请求.

最终代码:

thread_pool = ThreadPoolExecutor(2)
def go():
    all = selected_customer_all()
    return all
class R_SelectionCustomer(MyBackStargeRequestHandler):
    @authenticated  # 需要身份认证才能访问的处理器
    @tornado.web.asynchronous
    @gen.coroutine
    def get(self):
        print("我R_SelectionCustomer被访问了")
        #self.get_argument()
        all = yield thread_pool.submit(go)
        self.write(str(RJ(data=all,total=len(all))))
        # 采用两种装饰器的组合,finish会自动被调用        
        #self.finish()

四.后续

发现两个装饰器组合使用不需要再调用self.finish()!

五.拓展:

tornado.web.asynchronous:作用是保持长连接,也就是除非你主动调用self.finish()方法,否则requestHandler将不会返回。

tornado.gen.coroutine:使用协程的方式实现类似异步的处理效果。最新版的tornado,其实不一定需要写tornado.web.asynchronous装饰器

联系:@asynchronous会监听@gen.coroutine的返回结果(Future),并在@gen.coroutine装饰的代码段执行完成后自动调用finish。所以,就有两种方式来调用:

# -----------调用方式1---------------------
# 采用两种装饰器的组合,finish会自动被调用
@web.asynchronous
@gen.coroutine
def get(self):
    # ...some code...
    self.write('...')
# -----------调用方式2---------------------
@tornado.web.asynchronous
def get(self):
    self.my_func()

@tornado.gen.coroutine
def my_func(self):
    # ...some code...
    self.write('...')
    self.finish() # 此处需要手动调用finish

猜你喜欢

转载自blog.csdn.net/harry5508/article/details/84313659