0

in the documents of tornado is mentioned that gen.coroutine decorators are from older versions. newer should be used with aysnc. So far a I failed to convert that little code for Tornado 6.0.3.

import tornado.web
import tornado.websocket
import tornado.httpserver

from random import randint
from tornado import gen
from tornado.ioloop import IOLoop

from web_handlers import HandlerIndexPage
from web_handlers import HandlerWebSocket

msg = 'none'

@gen.coroutine
def generate_random_int():
    global msg
    while True:
        msg = str(randint(0, 100))
        print('generated:', msg)
        yield gen.sleep(1.0)

@gen.coroutine
def generate_message_to_sockets():
    global msg
    while True:
        print ('new messageToCon: ', msg)
        yield [con.write_message(msg) for con in HandlerWebSocket.connections]
        yield gen.sleep(1.0)


class webApplication(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r'/', HandlerIndexPage),
            (r'/websocket', HandlerWebSocket)
        ]

        settings = {
            'template_path': 'templates'
        }
        tornado.web.Application.__init__(self, handlers, **settings)

if __name__ == '__main__':
    ws_app = webApplication()
    server = tornado.httpserver.HTTPServer(ws_app)
    port = 9090
    server.listen(port)
    print('websocket listening on port:'+ str(port))
    IOLoop.current().spawn_callback(generate_random_int)
    IOLoop.current().spawn_callback(generate_message_to_sockets)
    IOLoop.instance().start()

How would I correctly use async ?

num3ri
  • 822
  • 16
  • 20
user3732793
  • 1,699
  • 4
  • 24
  • 53

2 Answers2

4

In Tornado, coroutines are generators that can be plugged into Python2 whereas async functions are first-class citizens in Python3. They have different semantics (for instance, you can return from an async function, but not a coroutine). The code you would need to change would look like:

...

import asyncio

...

async def generate_random_int():
    global msg
    while True:
        msg = str(randint(0, 100))
        print('generated:', msg)
        await gen.sleep(1.0)

async def generate_message_to_sockets():
    global msg
    while True:
        print ('new messageToCon: ', msg)
        futures = [con.write_message(msg) for con in HandlerWebSocket.connections]
        if futures:
            await asyncio.wait(futures)
        await gen.sleep(1.0)
...

You can see an example similar to your use-case here: https://www.tornadoweb.org/en/stable/ioloop.html#ioloop-objects

Chris Zacharias
  • 608
  • 5
  • 7
  • thanks for the reply but just changing only that ends up in "ValueError: Set of coroutines/Futures is empty." Probably I have to prepare the loop somehow different. Thanks for the link but I don't understand the example fully – user3732793 Oct 29 '19 at 01:10
  • You might need to defend against an empty set of connections rather than the way I did it. I would take the `[con.write_message...]` and assign it to a variable, then check if it is empty before trying to wait on it. – Chris Zacharias Oct 29 '19 at 01:22
  • oh man I was blind. Thanks pointing that out. And yes works :-) – user3732793 Oct 29 '19 at 07:41
1

Python 3.5 introduced the async and await keywords (functions using these keywords are also called “native coroutines”).

# Decorated:                    # Native:

# Normal function declaration
# with decorator                # "async def" keywords
@gen.coroutine
def a():                        async def a():
    # "yield" all async funcs       # "await" all async funcs
    b = yield c()                   b = await c()
    # "return" and "yield"
    # cannot be mixed in
    # Python 2, so raise a
    # special exception.            # Return normally
    raise gen.Return(b)             return b
Milovan Tomašević
  • 6,823
  • 1
  • 50
  • 42
  • this has been solve over a year ago and I think there is already a nativ solution – user3732793 Feb 08 '21 at 12:05
  • [here](https://stackoverflow.com/questions/45408840/asynchronous-login-tornado/66092857#66092857) you have basic example for login. And in the answer is written the way - [official rules](https://www.tornadoweb.org/en/stable/) how to get to it, which is irrelevant how old the solution is. – Milovan Tomašević Feb 08 '21 at 12:34