首页 > 解决方案 > 与另一个 asyncio 长时间运行的任务一起运行 Tornado

问题描述

我想asyncio在 Python 3.7 中运行 Tornado 服务器以及独立的长时间运行的任务。我是新手asyncio。我读过你应该只调用asyncio.run()一次,所以我把这两个任务放在了main()方法下,这样我就可以将一个参数传递给asyncio.run(). 当我运行这段代码时,我得到了错误TypeError: a coroutine was expected, got <function start_tornado at 0x105c8e6a8>。我想让代码在没有错误的情况下运行,但最终我想知道如何以正确的方式做到这一点。我在下面写的代码感觉就像一个丑陋的黑客。

import asyncio
import datetime
import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

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

# Fake background task I got from here:
# https://docs.python.org/3/library/asyncio-task.html#sleeping
async def display_date():
    while True:
        print(datetime.datetime.now())
        await asyncio.sleep(1)

async def start_tornado():
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

async def main():
    await asyncio.create_task(start_tornado)
    await asyncio.create_task(display_date)

asyncio.run(main())

标签: pythontornadopython-asyncio

解决方案


  1. create_task与函数一起使用时async def,正常调用该函数,然后将结果传递给create_task.

    await asyncio.create_task(start_tornado())
    await asyncio.create_task(display_date())
    
  2. create_task如果您要await立即使用,则无需使用。使用create_taskwithoutawait在后台启动任务,例如display_date(). start_tornado从这个意义上说,它不是后台任务,因为它没有无限循环,它只是启动了一个由 Tornado 放入后台的服务器。所以我会这样写:

    await start_tornado()
    asyncio.create_task(display_date())
    
  3. 从 Tornado 5.0 开始,Tornado IOLoop 和 asyncio 事件循环默认是集成的,所以你只需要启动一个,而不是两个都启动。所以只需删除IOLoop.start().start_tornado

  4. start_tornado目前没有做任何异步的事情,所以它可能只是一个正常的功能。但它也是一个合理的地方,可以添加异步启动逻辑,例如建立数据库连接,因此您可以将其保留为协程。

代码的工作版本与我的编辑:https ://repl.it/@bdarnell/FarawayAdmiredConversions


推荐阅读