Page MenuHomec4science

using_futures.diviner
No OneTemporary

File Metadata

Created
Mon, Aug 5, 05:00

using_futures.diviner

@title Using Futures
@group futures
Overview of how futures work in libphutil.
= Overview =
Futures (also called "Promises") are objects which represent the result of some
pending computation (like executing a command or making a request to another
server), but don't actually hold that result until the computation finishes.
They are used to simplify parallel programming, since you can pass the future
around as a representation for the real result while the real result is being
computed in the background. When the object is asked to return the actual
result, it blocks until the result is available.
libphutil provides a number of future-based APIs, as they strike a good balance
between ease of use and power for many of the domains where PHP is a reasonable
language choice.
Each type of future is used to do a different type of computation (for instance,
@{class:ExecFuture} executes system commands while @{class:HTTPFuture} executes
HTTP requests), but all of them behave in a basically similar way and can be
manipulated with the same top-level constructs.
= Basics =
You create a future by instantiating the relevant class and ask it to return the
result by calling ##resolve()##:
$gzip_future = new ExecFuture("gzip %s", $some_file);
$gzip_future->start();
// The future is now executing in the background, and you can continue
// doing computation in this process by putting code here.
list($err, $stdout, $stderr) = $gzip_future->resolve();
When you call ##resolve()##, the future blocks until the result is ready. You
can test if a future's result is ready by calling ##isReady()##:
$is_ready = $gzip_future->isReady();
Being "ready" indicates that the future's computation has completed and it will
not need to block when you call ##resolve()##.
Note that when you instantiate a future, it does not immediately initiate
computation. You must call ##start()##, ##isReady()## or ##resolve()## to
activate it. If you simply call ##resolve()## it will start, block until it is
complete, and then return the result, acting in a completely synchronous way.
See @{article:Command Execution} for more detailed documentation on how to
execute system commands with libphutil.
= Managing Multiple Futures =
Commonly, you may have many similar tasks you wish to parallelize: instead of
compressing one file, you want to compress several files. You can use the
@{class:FutureIterator} class to manage multiple futures, via the convenience
function @{function:Futures}.
$futures = array();
foreach ($files as $file) {
$futures[$file] = new ExecFuture("gzip %s", $file);
}
foreach (Futures($futures) as $file => $future) {
list($err, $stdout, $stderr) = $future->resolve();
if (!$err) {
echo "Compressed {$file}...\n";
} else {
echo "Failed to compress {$file}!\n";
}
}
@{function:Futures} takes a list of futures and runs them in parallel,
**returning them in the order they resolve, NOT the original list order**. This
allows your program to begin any followup computation as quickly as possible: if
the slowest future in the list happens to be the first one, you can finish
processing all the other futures while waiting for it.
You can also limit how many futures you want to run at once. For instance, to
process no more than 4 files simultaneously:
foreach (Futures($futures)->limit(4) as $file => $future) {
// ...
}
Consult the @{class:FutureIterator} documentation for detailed information on
class capabilities.

Event Timeline