-
#include "tensorstore/util/future.h"
-
template <typename T>
class [[nodiscard]] tensorstore::Future : public AnyFuture; “Consumer” interface to a one-time channel.
Future<T>
provides an interface for a consumer to asynchronously receive a value of typeT
or an error through aResult<T>
.In typical use, a consumer uses the
Future::ExecuteWhenReady
method to register a callback to be invoked when the shared state becomes ready. Alternatively,Future::result
may be called to synchronously wait for the result, blocking the current thread.Promise<T>
provides an interface for a producer to asynchronously send a value of typeT
or an error through aResult<T>
.In typical usage, an asynchronous operation initiator will create paired Future<T> and Promise<T> objects by invoking
PromiseFuturePair<T>::Make()
. From there, the asynchronous operation which returns a T can be installed on the Promise<>, typically putting the operation and the promise onto an executor or other thread pool, and storing the result of the operation on the promise, while returning the Future<> to the caller.Both
Promise<void>
andFuture<void>
are supported and return a Result<void>.Promise<T>
andFuture<T>
behave like reference counted pointers to a shared state that stores the actual value. In normal usage, there will be one or more instances ofPromise<T>
, and one or more instances ofFuture<T>
, all referring to the same shared state. The shared state is initially marked “not ready”, and transitions to the “ready” state when a producer sets the result. Once the state becomes “ready”, it cannot become “not ready”, and any further attempts to set the value have no effect.A limited form of cancellation is supported. Cancellation is signalled when all
Future<T>
instances referencing the shared state are destroyed or go out of scope before the operation completes. Using thePromise::ExecuteWhenNotNeeded
method, a producer may register callbacks to be invoked when either the shared state becomes ready or there are no more futures referencing the shared state.In addition to the producer -> consumer communication of a value or error, a limited form of consumer -> producer communication is also supported: a producer may defer performing certain work until the result is actually required. For example, this is useful if the deferred work may never be needed, or multiple deferred work items may be more efficiently handled together as a batch. On the consumer side, this is handled by the Future::Force method that may be invoked manually to indicate that the result is needed, and is also invoked automatically when a thread synchronously waits for the result. This calls any callbacks that a producer has registered using the
Promise::ExecuteWhenForced
method.This
Promise
/Future
implementation is executor-agnostic: all callbacks that are registered are either invoked immediately before the registration function returns (if the condition is already satisfied), or immediately by the thread that causes the condition to be satisfied (e.g. callingPromise::SetResult
,Future::Force
, or destroying the last Future or Promise referencing a given shared state). Therefore, the callbacks that are registered should not block or perform expensive computations; instead, any blocking or expensive computations should either be somehow deferred or run asynchronously on another thread. In addition, actions such as callingPromise::SetResult
,Future::Force
, and destroying a Promise or Future object should not be done while holding any exclusive locks that may be needed by a callback.Examples:
// Runs `function` asynchronously using `executor`, and returns a Future // representing the return value of `function`. template <typename T> Future<T> RunAsync(std::function<T()> function, Executor executor) { auto pair = PromiseFuturePair<T>::Make(); executor([promise = std::move(pair.promise), function = std::move(function)] { promise.SetResult(function()); }); return std::move(pair.future); } Future<void> future = RunAsync([]->void { std::count << " Async! " << std::endl; }, executor); future.Wait(); // Like `RunAsync`, except execution of `function` is deferred until // Force is called on the returned Future. template <typename T> Future<T> RunDeferred(std::function<T()> function, Executor executor) { auto pair = PromiseFuturePair<T>::Make(); pair.promise.ExecuteWhenForced([promise = std::move(pair.promise), function = std::move(function), executor = std::move(executor)] { executor([promise = std::move(promise), function = std::move(function)] { promise.SetResult(function()); }); }); return std::move(pair.future); } // Returns a Future representing the asynchronous addition of // `a.value()` and `b.value()`. Future<int> AddAsync1(Future<int> a, Future<int> b) { return PromiseFuturePair<int>::LinkValue( [](Promise<int> c, Future<int> a, Future<int> b) { c.SetResult(MapResult(std::plus<int>{}, a.result(), b.result())); }, std::move(a), std::move(b)).future; } // Equivalent to `AddAsync1`, showing usage of `MapFutureValue`. Future<int> AddAsync2(Future<int> a, Future<int> b) { return MapFutureValue(InlineExecutor{}, std::plus<int>{}, std::move(a), std::move(b)); } // Synchronously adds `a.value()` and `b.value()`. Result<int> AddSync1(Future<int> a, Future<int> b) { // In case `a` and `b` represent deferred computations, call Force on // both before blocking via `result()` to allow both computations to // run in parallel. a.Force(); b.Force(); return MapResult(std::plus<int>{}, a.result(), b.result()); } // Equivalent to `AddSync1`, showing how a Future-returning function can // be used synchronously. Result<int> AddSync2(Future<int> a, Future<int> b) { return AddAsync2(a, b).result(); }
- Template Parameters:¶
- typename T¶
Specifies the type of the value to be transmitted. The actual result value type is
Result<std::remove_const_t<T>>
.
Types¶
- type result_type;
The result type transmitted by the channel.
- using value_type = T;
The value type contained in the
result_type
.
Constructors¶
- Future(const Result<Future<U>>& result);
Constructs a Future from a
Result<Future<U>>
, whereU
isT
orconst U
isT
.
- Future(const absl::Status& status);
- Future(absl::Status&& status);
Construct a Future<T> with an an absl::Status code.
- Future(const Result<U>& result);
- Future(Result<U>&& result);
Construct a Future<T> from a Result<U>.
Methods¶
- void IgnoreFuture() const;
Ignores the future. This method signals intent to ignore the result to suppress compiler warnings from
[[nodiscard]]
.
- FutureCallbackRegistration ExecuteWhenReady(Callback&& callback) &&;
-
FutureCallbackRegistration
ExecuteWhenReady(Callback&& callback) const&; Registers a callback to invoke when
ready()
becomestrue
.
- std::add_lvalue_reference_t<result_type> result() const;
Calls
Force()
, waits for the result to be ready, and returns a reference to the result.
- std::add_lvalue_reference_t<T> value() const;
Equivalent to
result().value()
.
Related Constants¶
- constexpr bool tensorstore::IsFutureConvertible<SourceT, DestT>;
Bool-valued metafunction equal to
true
if, and only if,Future<SourceT>
is convertible toFuture<DestT>
.
Related Types¶
- using tensorstore::UnwrapFutureType<T>;
Alias that maps
Future<T>->T
,Result<T>->T
, or otherwiseT->T
.
- class tensorstore::FutureCallbackRegistration;
Handle to a registered Future or Promise callback, that may be used to unregister it.
- class [[nodiscard]] tensorstore::ReadyFuture<T> : public Future<T>;
Future that is guaranteed to be ready.
Related Functions¶
- ReadyFuture<T> tensorstore::MakeReadyFuture(U&&... u);
- ReadyFuture<const void> tensorstore::MakeReadyFuture();
Creates a
Future
in a ready state.
- Future<void> tensorstore::WaitAllFuture(Futures&&... future);
Creates a
future
tied to the completion of all the providedfuture
objects.
-
Future<void>
tensorstore::WaitAllFuture(span<const AnyFuture> futures); Creates a
Future
tied to the completion of all the providedfutures
objects.
Linking¶
-
FutureCallbackRegistration
tensorstore::Link(Callback&& callback,
Promise<PromiseValue> promise,
Futures&&... future); Creates a “link”, which ties a
promise
to one or morefuture
objects and acallback
.
-
FutureCallbackRegistration
tensorstore::LinkValue(Callback&& callback,
Promise<PromiseValue> promise,
Futures&&... future); Creates a “link”, which ties a
promise
to one or morefuture
objects and acallback
.
-
FutureCallbackRegistration
tensorstore::LinkError(Promise<PromiseValue> promise,
Futures&&... future); Creates a “link”, which ties a
promise
to one or morefuture
objects.
-
FutureCallbackRegistration
tensorstore::LinkResult(Promise<PromiseValue> promise,
Future<FutureValue> future); Creates a Link that moves a single Future’s result to a Promise.
Map functions¶
-
auto tensorstore::MapFuture(Executor&& executor,
Callback&& callback,
Future<FutureValue>... future); Returns a
Future
that resolves to the result of callingcallback(future.result()...)
when all of the specifiedfuture
objects become ready. Thecallback
is invoked using the specifiedexecutor
.
-
Future<UnwrapFutureType<std::remove_cvref_t<
std::invoke_result_t<Callback, FutureValue&...>>>>
tensorstore::MapFutureValue(Executor&& executor,
Callback&& callback,
Future<FutureValue>... future); Returns a
Future
that resolves tocallback(future.value()...)
when all of the specifiedfuture
objects become ready with non-error results. Thecallback
is invoked using the specifiedexecutor
.
-
Future<T> tensorstore::MapFutureError(Executor&& executor,
Func func,
Future<T> future); Transforms the error status of a Future.