7

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.

H2O
  • 612
  • 8
  • 18
  • The comment "Tornado will use concurrent.futures.Future if available" is outdated; Tornado 4.x always uses its own Future implementation. – Ben Darnell Jul 01 '15 at 22:30

1 Answers1

5

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.

drgarcia1986
  • 343
  • 1
  • 5
  • 1
    This works for me, thanks! I think I got it. I can't use 'raw' futures because they are not part of the IOLoop and I'd need some way to add them to that. Correct? – H2O Jul 01 '15 at 22:44
  • why couldn't you '''def async_fetch_future(): http_client = AsyncHTTPClient() my_future = Future() fetch_future = http_client.fetch('http://www.google.com')''' and then put this function into IOLOOP? – user2547081 Apr 14 '16 at 18:37