Menu
Reference
- Manticore\Ds
- Async
- Classes
- AggregateError
- CancellationToken
- CancelledException
- Channel
- ChannelClosedException
- Context
- DeadlockException
- Mutex
- Once
- Pool
- Received
- SelectCase
- Selected
- Semaphore
- Settled
- Task
- TaskGroup
- TimeoutException
- Functions
- async()
- awaitAll()
- awaitAllSettled()
- awaitAny()
- channel()
- delay()
- dump()
- dumpOn()
- failure()
- group()
- mapConcurrent()
- mapSettled()
- readFile()
- select()
- selectNow()
- selectWithin()
- shield()
- shutdownOn()
- spawn()
- stats()
- timeout()
- watchdog()
- writeFile()
- Http
- Http\WebSocket
- Buffer
- Process
- Io\Poll
- Manticore\Sapi
- Ffi
Once
final class Once
Run something exactly once, however many tasks ask for it.
The lazy initialiser: a connection pool, a parsed config. It exists because the work suspends; without it two tasks both see "not ready yet" and both build. Everyone who calls run() gets the same value, or the same error. Callers that arrive while the initialiser is running wait for it.
$pool = $once->run(fn() => buildPool());A cancelled initialiser is not a result: the state resets so the next caller can try again instead of inheriting someone else's cancellation. A failure other than cancellation is remembered and rethrown to every later caller.
Example
use Async\Once;
use function Async\async;
use function Async\awaitAll;
use function Async\delay;
use function Async\spawn;
async(function () {
$once = new Once();
$built = 0;
$get = function () use ($once, &$built) {
// The initialiser suspends, so without Once every caller would build.
return $once->run(function () use (&$built) {
$built++;
delay(0.01);
return "connection";
});
};
$results = awaitAll(spawn($get), spawn($get), spawn($get));
echo implode(",", $results), "\n";
echo "built $built time(s), hasRun: ", $once->hasRun() ? "yes" : "no", "\n";
});Output
connection,connection,connection
built 1 time(s), hasRun: yesSee also: Mutex
Methods
hasRun() | Whether the initialiser has finished, with a value or with an error. |
run() | Run $fn unless it already ran, and return its result. |
hasRun()#source
function hasRun(): bool
Whether the initialiser has finished, with a value or with an error.
Returns
bool โ true once finished; false while fresh, running or after a cancelled attempt
run()#source
function run(callable $fn): mixed
Run $fn unless it already ran, and return its result.
The first caller runs $fn; concurrent callers wait and receive its result. Later calls return the stored value, or rethrow the stored error, without calling $fn again.
Parameters
$fncallable- the initialiser, called with no arguments at most once
Returns
mixed โ the value $fn returned
Throws
- \Throwable
- whatever
$fnthrew, to every caller - CancelledException
- when the running initialiser or this waiting task is cancelled
Example
use Async\Once;
use function Async\async;
use function Async\awaitAll;
use function Async\delay;
use function Async\spawn;
async(function () {
$once = new Once();
$built = 0;
$get = function () use ($once, &$built) {
// The initialiser suspends, so without Once every caller would build.
return $once->run(function () use (&$built) {
$built++;
delay(0.01);
return "connection";
});
};
$results = awaitAll(spawn($get), spawn($get), spawn($get));
echo implode(",", $results), "\n";
echo "built $built time(s), hasRun: ", $once->hasRun() ? "yes" : "no", "\n";
});Output
connection,connection,connection
built 1 time(s), hasRun: yes