2

Thanks to this post, I am trying out the asynchronous driver tornado-redis. From the demo (Github example), it shows that how to do asynchronous gets using this library, but it is not clear to me that if the sets are asynchronous too (they do have a callback function).

So if possible, what is the correct way of doing asynchronous writes using tornado-redis? Would it be something like this:

@tornado.web.asynchronous
@tornado.gen.engine
def post(self):
    ...
    yield tornado.gen.Task(t.set,'key', 'value')
Community
  • 1
  • 1
MLister
  • 10,022
  • 18
  • 64
  • 92

1 Answers1

3

Look at the tornado-redis code. Client.set method has following defenition:

def set(self, key, value, callback=None):
    self.execute_command('SET', key, value, callback=callback)

So yes, it takes callback and can be used with gen.Task.

Correct ways to write asynchronously:

  1. Way you described in question, using gen.
  2. Way, described in github example.

Example from github:

c = tornadoredis.Client()
c.connect()

def on_set(result):
    log.debug("set result: %s" % result)

c.set('foo', 'Lorem ipsum #1', on_set)
c.set('bar', 'Lorem ipsum #2', on_set)
c.set('zar', 'Lorem ipsum #3', on_set)

Separate class with gen module:

class MyRedisWrapper(object):
    @gen.engine
    def set(self, key, value):
        yield tornado.gen.Task(t.set, key, value)

r = MyRedisWrapper()

class MyHandler(tornado.web.RequestHandler):
    def get(self):
        r.set('key', 'value') #It will work, but not sure about efficiency.
Nikolay Fominyh
  • 8,946
  • 8
  • 66
  • 102
  • thanks. Can I use the `gen` approach inside a custom class in an Tornado app, that is, *not* inside a RequestHandler class/subclass. If not, how should I use it asynchronously in such case? By supplying a callback to the get/set methods as in the second option above? – MLister Aug 03 '12 at 21:54
  • `gen` is syntactic sugar, so yes. You can use `gen.engine` at any method. – Nikolay Fominyh Aug 03 '12 at 22:40
  • looking at: http://www.tornadoweb.org/documentation/gen.html#decorator, to be more precise, `gen.engine` should only be used for an async method. In your 'separate class' example above, the `set` method is not async? – MLister Aug 03 '12 at 23:11
  • `t.set` is async. If you will use `gen.Task` on not async method - it will throw argument error, like in this question http://stackoverflow.com/questions/11679040/using-gen-task-with-tornado-for-a-simple-function. – Nikolay Fominyh Aug 03 '12 at 23:20
  • 1
    Sorry I am a bit confused, the documentation says 'it doesn’t make sense to use gen.engine on functions that don’t already take a callback argument'. In the example above, what is the callback argument for the `set(self, key, value)` method (`t.set` is different and I presume that by which you mean the `tornadoredis` method). – MLister Aug 03 '12 at 23:57
  • It doesn't make sense to use `yield gen.Task` with functions that don't take `callback` argument. What are you trying to achieve? – Nikolay Fominyh Aug 04 '12 at 11:55
  • I'm just trying to understand how this guideline: '`it doesn’t make sense to use gen.engine on functions that don’t already take a callback argument`' applies to the example above for the `set(self, key, value)` method inside `MyRedisWrapper` class? This method does not have a callback argument, does it? Yet, you're using a `gen.engine` decorator on it. – MLister Aug 05 '12 at 15:00
  • When you write simple `get` in request handler - you write `gen.engine` also, but `get` doesn't take `callback` argument. I think, that you shouldn't use `gen.engine` if you only use functions that don't take callback inside decorated method. – Nikolay Fominyh Aug 05 '12 at 16:06