Issue
I would like to run a Tornado server alongside an independent long-running task in asyncio
in Python 3.7. I'm new to asyncio
. I've read that you should only call asyncio.run()
once, so I've brought both tasks together under the main()
method so that I can pass a single argument to asyncio.run()
. When I run this code, I get the error TypeError: a coroutine was expected, got <function start_tornado at 0x105c8e6a8>
. I'd like to get the code to run without errors, but ultimately I want to know how to do this the right way. The code I've written below feels like an ugly 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())
Solution
When you use
create_task
with anasync def
function, call the function normally and then pass the result tocreate_task
.await asyncio.create_task(start_tornado()) await asyncio.create_task(display_date())
You don't need to use
create_task
if you're going toawait
it immediately. Usecreate_task
withoutawait
to start tasks in the background, likedisplay_date()
.start_tornado
is not a background task in this sense because it doesn't have an infinite loop, it just starts a server that is put into the background by Tornado. So I'd write it like this:await start_tornado() asyncio.create_task(display_date())
Since Tornado 5.0, the Tornado IOLoop and asyncio event loop are integrated by default, so you only need to start one, not both. So just remove the
IOLoop.start()
call instart_tornado
.start_tornado
isn't currently doing anything asynchronous, so it could just be a normal function. But it would also be a reasonable place to add asynchronous startup logic like establishing database connections, so you can keep it as a coroutine.
Working version of the code with my edits: https://repl.it/@bdarnell/FarawayAdmiredConversions
Answered By - Ben Darnell
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.