Tornado 6.1 非阻塞请求

Posted

技术标签:

【中文标题】Tornado 6.1 非阻塞请求【英文标题】:Tornado 6.1 non-blocking request 【发布时间】:2021-08-28 08:31:06 【问题描述】:

使用 Tornado,我有一个需要很长时间的 POST 请求,因为它向另一个 API 服务发出许多请求并处理数据。这可能需要几分钟才能完全完成。我不希望这会阻止整个 Web 服务器响应它当前所做的其他请求。

我在 SO 上查看了多个线程,但它们通常已有 8 年历史,并且由于 tornado 从 tornado.gen 中删除了“引擎”组件,因此代码不再工作。

有没有一种简单的方法可以启动这个漫长的 get 调用,并且不会让它在此过程中阻塞整个 Web 服务器?有什么我可以在代码中说的......“提交 POST 响应并处理这一功能,而不会阻止任何并发服务器请求获得即时响应”?

示例: main.py

def make_app():
        return tornado.web.Application([
                (r"/v1", MainHandler),
                (r"/v1/addfile", AddHandler, dict(folderpaths = folderpaths)),
                (r"/v1/getfiles", GetHandler, dict(folderpaths = folderpaths)),
                (r"/v1/getfile", GetFileHandler, dict(folderpaths = folderpaths)),
                ])




if __name__ == "__main__":
        
        app = make_app()
        sockets = tornado.netutil.bind_sockets(8888)
        tornado.process.fork_processes(0)
        tornado.process.task_id()
        server = tornado.httpserver.HTTPServer(app)
        server.add_sockets(sockets)
        tornado.ioloop.IOLoop.current().start()

addHandler.py



class AddHandler(tornado.web.RequestHandler):
    
    def initialize(self, folderpaths):
        self.folderpaths = folderpaths


    def blockingFunction(self):
        time.sleep(320)
        post("AWAKE")

    def post(self):

        user = self.get_argument('user')
        folderpath = self.get_argument('inpath')
        outpath = self.get_argument('outpath')
        workflow_value = self.get_argument('workflow')

        status_code, status_text = validateInFolder(folderpath)

        
        if (status_code == 200):
            logging.info("Status Code 200")
            result = self.folderpaths.add_file(user, folderpath, outpath, workflow_value)
            self.write(result)
            self.finish()

            #At this point the path is validated.
            #POST response should be send out. Internal process should continue, new 
            #requests should not be blocked
            
            self.blockingFunction()

想法是,如果输入参数得到验证,则应该发送 POST 响应。 然后应该启动内部进程 (blockingFunction()),它不应该阻止 Tornado 服务器处理另一个 API POST 请求。

我尝试将 (blockingFunction()) 定义为异步,这允许我处理多个并发用户请求 - 但是有一个关于异步方法缺少“等待”的警告。

欢迎任何帮助。谢谢

【问题讨论】:

使用run_in_executor 在单独的线程中运行阻塞函数。如果您只是发送 http 请求(而不执行任何 cpu 阻塞任务),那么使用 AsyncHTTPClient 将获得比线程更好的性能。 你好@xyres 谢谢你的回复。我查看了'run_in_executor' 我尝试像这样调用函数:await loop.run_in_executor(None, self.blockingFunction()) 同时将 def post(self) 声明为'async' - 并在 def post( self): loop = asyncio.get_running_loop() - 但是我仍然遇到同样的问题。知道应该改变什么吗? ---(P.S.:我稍后将值写入数据库,所以我认为 run_in_executor 看起来比使用 AsynchHTTPClient 更有希望) 编辑:tornadoweb.org/en/stable/faq.html 我原来的 liveblockingFunction() 有参数,需要像这样调用:await loop.run_in_executor(None, self.blockingFunction, param1, param2) 似乎有了这个改变工作。谢谢@xyres 该方法,xyres 说,可能更好。run_in_executor 是执行任何 cpu 阻塞任务时更好的方法(你说,只是可能请求,而不是 cpu 阻塞)。它使用线程池或里面的进程池,会占用更多的资源。 【参考方案1】:
class AddHandler(tornado.web.RequestHandler):
    
    def initialize(self, folderpaths):
        self.folderpaths = folderpaths


    def blockingFunction(self):
        time.sleep(320)
        post("AWAKE")

    async def post(self):

        user = self.get_argument('user')
        folderpath = self.get_argument('inpath')
        outpath = self.get_argument('outpath')
        workflow_value = self.get_argument('workflow')

        status_code, status_text = validateInFolder(folderpath)

        
        if (status_code == 200):
            logging.info("Status Code 200")
            result = self.folderpaths.add_file(user, folderpath, outpath, workflow_value)
            self.write(result)
            self.finish()

            #At this point the path is validated.
            #POST response should be send out. Internal process should continue, new 
            #requests should not be blocked

            await loop.run_in_executor(None, self.blockingFunction)

            #if this had multiple parameters it would be 
            #await loop.run_in_executor(None, self.blockingFunction, param1, param2)

谢谢@xyres

进一步阅读:https://www.tornadoweb.org/en/stable/faq.html

【讨论】:

以上是关于Tornado 6.1 非阻塞请求的主要内容,如果未能解决你的问题,请参考以下文章

Python web框架 Tornado异步非阻塞

利用tornado使请求实现异步非阻塞

tornado异步请求非阻塞-乾颐堂

python---tornado补充(异步非阻塞)

Tornado 异步非阻塞

Tornado----自定义异步非阻塞Web框架:Snow