简体   繁体   中英

Using Twisted's @inlineCallbacks with Tornado's @gen.engine

Tornado/Twisted newb here. First I just want to confirm what I know (please correct and elaborate if I am wrong):

In order to use @gen.engine and gen.Task in Tornado, I need to feed gen.Task() functions that are:

  • asynchronous to begin with
  • has the keyword argument "callback"
  • calls the callback function at the very end

In other words the function should look something like this:

def function(arg1, arg2, ... , callback=None):

    # asynchronous stuff here ...

    callback()

And I would call it like this (trivial example):

@gen.engine
def coroutine_call():

    yield gen.Task(function, arg1, arg2)

Now I am in a weird situation where I have to use Twisted in a Tornado system for asynchronous client calls to a server (since Tornado apparently does not support it).

So I wrote a function in Twisted (eg connects to the server):

import tornado.platform.twisted
tornado.platform.twisted.install()
from twisted.web.xmlrpc import Proxy

class AsyncConnection():
    def __init__(self, hostname):
        self.proxy = Proxy(hostname)
        self.token = False

    @defer.inlineCallbacks
    def login(self, user, passwd, callback=None):
        """Login to server using given username and password"""

        self.token = yield self.proxy.callRemote('login', user, passwd) # twisted function
        callback()

And if I run it like so:

@gen.engine
def test():

    conn = AsyncConnection("192.168.11.11")
    yield gen.Task(conn.login, "user","pwd")
    print conn.token

if __name__ == '__main__':
    test()
    tornado.ioloop.IOLoop.instance().start()

And I DO get the token as I want. But my question is:

I know that Twisted and Tornado can share the same IOLoop. But am I allowed to do this (ie use @defer.inlineCallbacks function in gen.Task simply by giving it the callback keyword argument)? I seem to get the right result but is my way really running things asynchronously? Any complications/problems with the IOLoop this way?

I actually posted somewhat related questions on other threads

Is it possible to use tornado's gen.engine and gen.Task with twisted?

Using Tornado and Twisted at the same time

and the answers told me that I should "wrap" the inlineCallback function. I was wondering if adding the callback keyword is enough to "wrap" the twisted function to be suitable for Tornado.

Thanks in advance

What you're doing is mostly fine: adding a callback argument is enough to make a function usable with gen.Task. The only tricky part is exception handling: you'll need to run the callback from an except or finally block to ensure it always happens, and should probably return some sort of value to indicate whether the operation succeeded or not (exceptions do not reliably pass through a gen.Task when you're working with non-Tornado code)

The wrapper approach (which I posted in Is it possible to use tornado's gen.engine and gen.Task with twisted? ) has two advantages: it can be used with most Twisted code directly (since Twisted functions usually don't have a callback argument), and exceptions work more like you'd expect (an exception raised in the inner function will be propagated to the outer function).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM