Skip to main content
A Future object tracks execution of a function call or another operation like map or reduce in a Tensorlake Application. A Future object is returned when you start an operation defined by an Awaitable object using its run method. See more about Awaitables and tail calls. The Future object can be used to get the result of the operation once it completes.
from tensorlake.applications import application, function, Future

@application()
@function()
def my_application(name: str) -> str:
    # Creates Awaitable object for the `capitalize(name)` function call and runs it immediately.
    # `.run()` method doesn't block the calling function until the function call completes.
    # It returns a Future object that can be used to get the result of the function call later.
    capitalized_name_future: Future = capitalize.awaitable(name).run()
    # Blocks until the `capitalize` function call completes and get its return value.
    capitalized_name: str = capitalized_name_future.result()
    return f"Hello, {capitalized_name}!"


@function()
def capitalize(text: str) -> str:
    return text.upper()
The main purpose of Futures is to allow running multiple function calls in parallel and getting their results later. This allows building applications that can process multiple independent tasks concurrently, reducing overall latency. This is why Future class interface is inspired by the standard concurrent.futures.Future class in Python. Class method Future.wait(futures: Iterable[Future], timeout: float|None = None, return_when=RETURN_WHEN.ALL_COMPLETED) -> None can be used to wait for multiple Futures to complete. This class method is inspired by the standard concurrent.futures.wait in Python.

Example: Running multiple function calls in parallel

from tensorlake.applications import application, function, Awaitable, Future, RETURN_WHEN

@application()
@function()
def greet(name: str) -> str:
    # Start two function calls in parallel.
    capitalized_name: Future = capitalize.awaitable(name).run()
    joke: Future = make_joke.awaitable(name).run()
    # Wait for both function calls to complete.
    Future.wait([capitalized_name, joke], return_when=RETURN_WHEN.ALL_COMPLETED)
    # Call `say_hello_and_say_joke` with the values returned by both function calls.
    # Block until `say_hello_and_say_joke` completes and return its return value.
    return say_hello_and_say_joke(capitalized_name.result(), joke=joke.result())


@function()
def say_hello_and_say_joke(name: str, joke: str) -> str:
    return f"Hello, {name}! Here's a joke for you: {joke}"


@function()
def capitalize(text: str) -> str:
    return text.upper()


@function()
def make_joke(name: str) -> str:
    return f"Why did {name} cross the road? To get to the other side!"

Waiting for multiple Futures to complete

Future.wait class method can be used to wait for multiple Futures to complete. This class method is inspired by the standard concurrent.futures.wait in Python. It’s full signature is:
from tensorlake.applications import Future, RETURN_WHEN

Future.wait(
    futures: Iterable[Future],
    timeout: float|None = None,
    return_when=RETURN_WHEN.ALL_COMPLETED
) -> None
  • futures: An iterable of Future objects to wait for.
  • timeout: An optional timeout in seconds. If specified, the method will return after the timeout even if not all Futures have completed.
  • return_when: A flag indicating when to return. It can be one of the following values from the RETURN_WHEN enum:
    • RETURN_WHEN.ALL_COMPLETED: Wait until all Futures have completed.
    • RETURN_WHEN.FIRST_COMPLETED: Wait until at least one Future has completed.
    • RETURN_WHEN.FIRST_EXCEPTION: Wait until at least one Future has raised an exception or all have completed.
The method return a tuple of two lists: (done, not_done), where done is a list of Futures that have completed, and not_done is a list of Futures that have not completed yet.

Future object

Future object has the following methods and properties:
  • id -> str: A unique identifier for the Future object in scope of the current application request.
  • exception -> Exception|None: If the function call associated with this Future raised an exception, this property will return the exception object. Otherwise, it will return None. If the function call is not yet complete, this property will also return None.
  • result(timeout: float|None = None) -> Any: Blocks until the Future completes and returns the result of the function call. If the function call raised an exception, the FunctionCallFailure will be raised here. See more about error handling. An optional timeout in seconds can be specified. If timeout is reached before the Future completes, a TimeoutError will be raised.
  • done() -> bool: Returns True if the Future has completed (either successfully or with an exception), otherwise returns False.

Limitations

Currently a Future object cannot be passed as a function argument or returned as a tail call. This might change in the future.