Proxy Futures¶
Last updated 1 November 2023
This guide walks through the use of the
Store.future()
interface and associated
Future
.
Note
Some familiarity with ProxyStore is assumed. Check out the Get Started guide and Concepts page to learn more about ProxyStore's core concepts.
Warning
The Store.future()
and
Future
interfaces are
experimental features and may change in future releases.
The Future
interface enables
a data producer to preemptively send a proxy to a data consumer before the
target data has been created. The consumer of the target data proxy will
block when the proxy is first used and resolved until the producer
has created the target data.
Here is a trivial example using a Store
and
LocalConnector
. The
future.proxy()
method is used
to create a Proxy
which will resolve to the
result of the future.
Info
Not all Connector
implementations are compatible with the
Store.future()
interface.
The Connector
instance used
to initialize the Store
must also
implement the
DeferrableConnector
protocol. A NotImplementedError
will be
raised when calling Store.future()
if the connector is not an instance of
DeferrableConnector
.
Many of the out-of-the-box implementations implement the
DeferrableConnector
protocol such as the
EndpointConnector
,
FileConnector
, and
RedisConnector
.
The power of Future
comes when
the data producer and consumer are executing independently in time and space
(i.e., execution occurs in different processes, potentially on different
systems, and in an undefined order). The
Future
enables the producer
and consumer to share a data dependency, while allowing the consumer to
eagerly start execution before the data dependencies are fully satisfied.
Consider the following example where we have a client which invokes two
functions, foo()
and bar()
on remote processes. foo()
will produce an
object needed by bar()
, but we want to start executing foo()
and bar()
at the same time. (We could even start bar()
before foo()
!)
In this example, foo()
and bar()
started executing at the same time.
This allows bar()
to eagerly execute code which does not depend on the
data produced by foo()
. bar()
will only block once the data is needed by
the computation.