为啥在 Tornado 服务器 Post 方法中创建线程会产生运行时错误?

Posted

技术标签:

【中文标题】为啥在 Tornado 服务器 Post 方法中创建线程会产生运行时错误?【英文标题】:Why creating a thread inside Tornado server Post method gives Runtime error?为什么在 Tornado 服务器 Post 方法中创建线程会产生运行时错误? 【发布时间】:2018-02-03 09:53:41 【问题描述】:

我已经编写了一个 Tornado HTTP 服务器,并尝试在 API 请求 http://localhost:8889/img 被命中后立即启动一个线程。一段时间后或立即出现 RuntimeError 异常。无法理解这种行为。请解释一下。

import tornado.ioloop
import tornado.web
import threading
import time
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
class img(tornado.web.RequestHandler):
    def post(self):
        t_img = threading.Thread(target=self.sendimg,)
        t_img.start()

    def sendimg(self):
        while True:
            self.write("name":"vinay")
            print("sent")
            time.sleep(0.5)

def make_app():
    return tornado.web.Application([
    (r"/", MainHandler),
    (r"/img", img),
    ])

if __name__ == "__main__":
    app = make_app()
    app = tornado.httpserver.HTTPServer(app)
    app.listen(8889)
    tornado.ioloop.IOLoop.current().start()

错误:

  self.write("name":"vinay")
    File "/Users/vinaykp/anaconda3/lib/python3.6/site-
    packages/tornado/web.py", line 708, in write
      raise RuntimeError("Cannot write() after finish()")
    RuntimeError: Cannot write() after finish()

【问题讨论】:

【参考方案1】:

我不是并发和 Tornado 方面的专家,但似乎主要问题在于请求对象的生命周期。看,当你将 img 类传递给 tornado.web.Application 时:

def make_app():
    return tornado.web.Application([
    (r"/", MainHandler),
    (r"/img", img),
    ])

Tornado 接收到类的引用,创建它的对象并执行正确的方法。随着请求完成并且客户端从服务器获得响应 - 没有什么可做的了。一旦请求完成并处于“完成”状态,您就不能向客户write,因为这完全没有意义,因为目前客户对您没有任何期望。

如果您想到 HTTP 设计,这就是该协议的工作原理。这不是持续的连接,而是无状态的请求-响应通信,它有其开始和结束,另一方面决定了请求的生命周期。

您当然可以在服务器收到请求时启动新线程,例如:

def get(self):
    self.write("Hello, world!")
    tf = threading.Thread(target=self.thread_func)
    tf.start()

def thread_func(self):
    while True:
        print("ok\n")
        time.sleep(0.5)

每次你通过请求到达正确的端点时都会创建新线程,但是在请求完成后你不能再真正写到self

【讨论】:

..好的。如果 API 被多次命中,我觉得是对的。但对我来说,API 只会命中一次,并且该线程将被启动。一段时间后引发运行时异常。 api 被击中多次还是仅仅一次都没关系。您不能对已完成请求的对象执行self.write,因为该请求不再向 API 客户端提供任何服务,因为它的生命周期已结束。一段时间后出现运行时异常,因为您的线程在其中休眠,并且在休眠后尝试写入RequestHandler

以上是关于为啥在 Tornado 服务器 Post 方法中创建线程会产生运行时错误?的主要内容,如果未能解决你的问题,请参考以下文章

python tornado写的web服务器脚本,运行时每过一会儿都会发出如下警告,这是怎么回事儿? 该如何解决?

tornado基本使用一

为啥我不能在 Wordpress 中创建新帖子?警告:从第 716 行 /public_html/wp-admin/includes/post.php 中的空值创建默认对象

如何在 Tornado 中创建多个 websocket 聊天?

Tornado的入门研究

Tornado之Session实现