Search code examples
pythontornado

Can't call result() on futures in tornado


I want to do some asynchronous HTTP-requests using the python library tornado (version 4.2). I can however not force a future to complete (using result()) since I get an Exception: "DummyFuture does not support blocking for results".

I have python 3.4.3 therefore future support should be part of the standard library. The documentation of concurrent.py says:

Tornado will use concurrent.futures.Future if it is available; otherwise it will use a compatible class defined in this module.

A minimal example for what I am trying to do is provided below:

from tornado.httpclient import AsyncHTTPClient;

future = AsyncHTTPClient().fetch("http://google.com")
future.result()

If I understand my problem correctly it occurs because the import of concurrent.futures.Future somehow is not used. The relevant code in tornado appears to be in concurrent.py but I am not really making progress on understanding where exactly the problem lies.


Solution

  • Try to create another Future and use add_done_callback:

    From Tornado documentation

    from tornado.concurrent import Future
    
    def async_fetch_future(url):
        http_client = AsyncHTTPClient()
        my_future = Future()
        fetch_future = http_client.fetch(url)
        fetch_future.add_done_callback(
            lambda f: my_future.set_result(f.result()))
        return my_future
    

    But you still need solve the future with the ioloop, like this:

    # -*- coding: utf-8 -*-
    from tornado.concurrent import Future
    from tornado.httpclient import AsyncHTTPClient
    from tornado.ioloop import IOLoop
    
    
    def async_fetch_future():
        http_client = AsyncHTTPClient()
        my_future = Future()
        fetch_future = http_client.fetch('http://www.google.com')
        fetch_future.add_done_callback(
            lambda f: my_future.set_result(f.result()))
        return my_future
    
    response = IOLoop.current().run_sync(async_fetch_future)
    
    print(response.body)
    

    Another way to this, is using tornado.gen.coroutinedecorator, like this:

    # -*- coding: utf-8 -*-
    from tornado.gen import coroutine
    from tornado.httpclient import AsyncHTTPClient
    from tornado.ioloop import IOLoop
    
    
    @coroutine
    def async_fetch_future():
        http_client = AsyncHTTPClient()
        fetch_result = yield http_client.fetch('http://www.google.com')
        return fetch_result
    
    result = IOLoop.current().run_sync(async_fetch_future)
    
    print(result.body)
    

    coroutine decorator causes the function to return a Future.