运行 Tornado 和另一个 asyncio long-运行 任务
Run Tornado alongside another asyncio long-running task
我想在 Python 3.7 的 asyncio
中 运行 一个 Tornado 服务器和一个独立的长期 运行ning 任务。我是 asyncio
的新手。我读到你应该只调用 asyncio.run()
一次,所以我将两个任务放在 main()
方法下,这样我就可以将一个参数传递给 asyncio.run()
。当我 运行 这段代码时,我得到错误 TypeError: a coroutine was expected, got <function start_tornado at 0x105c8e6a8>
。我想获得 运行 的代码而不会出错,但最终我想知道如何以正确的方式做到这一点。我在下面编写的代码感觉像是一个丑陋的 hack。
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())
当您将create_task
与async def
函数一起使用时,请正常调用该函数,然后将结果传递给create_task
。
await asyncio.create_task(start_tornado())
await asyncio.create_task(display_date())
如果您要立即 await
,则无需使用 create_task
。使用不带 await
的 create_task
在后台启动任务,如 display_date()
。 start_tornado
在这个意义上不是后台任务,因为它没有无限循环,它只是启动一个由 Tornado 置于后台的服务器。所以我会这样写:
await start_tornado()
asyncio.create_task(display_date())
从Tornado 5.0开始,默认集成了Tornado IOLoop和asyncio event loop,所以只需要启动一个,不需要同时启动两个。所以只需删除 start_tornado
中的 IOLoop.start()
调用即可。
start_tornado
目前没有做任何异步的事情,所以它可能只是一个普通的函数。但它也是添加异步启动逻辑(如建立数据库连接)的合理位置,因此您可以将其保留为协程。
经过我编辑的代码的工作版本:https://repl.it/@bdarnell/FarawayAdmiredConversions
Tornado 可能已经拥有您需要的一切。
- 您可以使用
tornado.ioloop.IOLoop.current().add_callback
而不是 await asyncio.create_task
- 您可以使用
yield gen.sleep(1)
而不是 await asyncio.sleep(1)
所以最后您示例中的整个代码可能如下所示:
import datetime
import tornado.ioloop
import tornado.web
import tornado.gen as gen
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
@gen.coroutine
def display_date():
while True:
print(datetime.datetime.now())
yield gen.sleep(1)
def start_tornado():
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().add_callback(display_date)
tornado.ioloop.IOLoop.current().start()
start_tornado()
我想在 Python 3.7 的 asyncio
中 运行 一个 Tornado 服务器和一个独立的长期 运行ning 任务。我是 asyncio
的新手。我读到你应该只调用 asyncio.run()
一次,所以我将两个任务放在 main()
方法下,这样我就可以将一个参数传递给 asyncio.run()
。当我 运行 这段代码时,我得到错误 TypeError: a coroutine was expected, got <function start_tornado at 0x105c8e6a8>
。我想获得 运行 的代码而不会出错,但最终我想知道如何以正确的方式做到这一点。我在下面编写的代码感觉像是一个丑陋的 hack。
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())
当您将
create_task
与async def
函数一起使用时,请正常调用该函数,然后将结果传递给create_task
。await asyncio.create_task(start_tornado()) await asyncio.create_task(display_date())
如果您要立即
await
,则无需使用create_task
。使用不带await
的create_task
在后台启动任务,如display_date()
。start_tornado
在这个意义上不是后台任务,因为它没有无限循环,它只是启动一个由 Tornado 置于后台的服务器。所以我会这样写:await start_tornado() asyncio.create_task(display_date())
从Tornado 5.0开始,默认集成了Tornado IOLoop和asyncio event loop,所以只需要启动一个,不需要同时启动两个。所以只需删除
start_tornado
中的IOLoop.start()
调用即可。start_tornado
目前没有做任何异步的事情,所以它可能只是一个普通的函数。但它也是添加异步启动逻辑(如建立数据库连接)的合理位置,因此您可以将其保留为协程。
经过我编辑的代码的工作版本:https://repl.it/@bdarnell/FarawayAdmiredConversions
Tornado 可能已经拥有您需要的一切。
- 您可以使用
tornado.ioloop.IOLoop.current().add_callback
而不是 - 您可以使用
yield gen.sleep(1)
而不是
await asyncio.create_task
await asyncio.sleep(1)
所以最后您示例中的整个代码可能如下所示:
import datetime
import tornado.ioloop
import tornado.web
import tornado.gen as gen
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
@gen.coroutine
def display_date():
while True:
print(datetime.datetime.now())
yield gen.sleep(1)
def start_tornado():
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().add_callback(display_date)
tornado.ioloop.IOLoop.current().start()
start_tornado()