1

I need to change the following legacy tornado code to call an async function async def my_async1(self).

class MyHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self, action):
        ....
        

Can they be mixed? How to refactory the code?

class MyHandler(tornado.web.RequestHandler):
    @gen.coroutine 
    async def get(self, action):
        ....
        await self.my_async() # ? 
     

Can I just remove @gen.coroutine and add async? Are they exactly the same?

ca9163d9
  • 27,283
  • 64
  • 210
  • 413

1 Answers1

3

Yeah, they are almost the same. @gen.coroutine is from old days when Python didn't have async/await keywords. So @gen.coroutine was used for turning regular functions (or generators) into asynchronous generators.

For newer python versions (3.5+), the async/await syntax should be preferred over @gen.coroutine.

Keep these things in mind while converting the functions:

  1. Don't decorate async def functions with @gen.coroutine (like you've done in your second code example).
  2. Replace yield keyword with await keyword.
  3. yield None statement works but await None doesn't.
  4. You can yield a list (such as yield [f1(), f2()]), but with await, use await gen.multi(f1(), f2()) or await asyncio.gather(f1(), f2()). (Thanks to Ben for mentioning this.)
xyres
  • 20,487
  • 3
  • 56
  • 85
  • Curiously, the code has to import tornado before Python 3.5? Since `gen.coroutine` is in tornado. BTW, you said *almost the same*, what's the difference if they are not identical? – ca9163d9 Nov 03 '20 at 05:57
  • @ca9163d9 `@gen.coroutine` is for generators (with `yield` statements), whereas a `async def` functions are actual coroutines (with `await` statements). Otherwise, they work pretty much the same. – xyres Nov 03 '20 at 06:15
  • 1
    There are a few things that work a little differently. For example, in `@gen.coroutine` you can do `yield [f1(), f2()]` to do things in parallel. In `async def`, you have to use a wrapper object like `await gen.multi(f1(), f2())` or `await asyncio.gather(f1(), f2())` – Ben Darnell Nov 03 '20 at 21:16
  • 1
    Slight modification worked for me. Instead of await gen.multi(f1(), f2()), pass a list of the functions in. Looks like this: await gen.multi([f1(), f2()]) – Zach Rieck Feb 26 '21 at 21:30