phasync
Manual
The manual is a set of topic books. Each has an introduction, concepts, guides, examples and the reference for the classes and functions that belong to it.
Coroutines#
Start, await and yield: run(), go(), await(), and the model they share.
- Introduction
- Coroutines – How coroutines, frames and cancellation work.
- Threads and concurrency – What runs at the same time, and what only looks like it.
- Design – Why phasync and Swerve are built the way they are.
- Examples – Every example in this topic, with its output.
phasync– The static API of phasync: start coroutines, wait for them, cancel them, and wait for streams and flags.phasync::run– Runs $fn and returns its result once it and every coroutine started inside it have ended.phasync::go– Starts $fn as a coroutine in the current frame and scope, and returns it, without waiting for it.phasync::await– Waits for a coroutine or a promise, and returns its result or throws the exception it ended with.phasync::yield– Suspends the current coroutine until the loop has made its next round, after the coroutines that were ready have run.AggregateException– More than one thing failed in one run(): what $fn threw and the failures of coroutines nobody awaited, or several of those.RethrowExceptionInterface– Marks the exceptions that phasync rethrows with a stack trace that begins in the code that called phasync, not inside it.
Waiting and timeouts#
Sleep, wait for a stream or a flag, and what happens when the wait runs out.
- Introduction
- Examples – Every example in this topic, with its output.
phasync::sleep– Pauses the current coroutine for $seconds, and lets the others run meanwhile.phasync::idle– Suspends the current coroutine until the event loop has had nothing to run for at least $after seconds: the ready queue and the callback queue are both empty, and an immediate poll finds no I/O ready.phasync::readable– Suspends the coroutine until the stream can be read without blocking, and returns the stream.phasync::writable– Suspends the coroutine until the stream can be written without blocking, and returns the stream.phasync::raiseFlag– Wakes every coroutine waiting for $signal in phasync::awaitFlag, and returns how many it woke.phasync::awaitFlag– Suspends the current coroutine until $signal is raised with phasync::raiseFlag.IOException– A stream wait failed: the value was no stream, the stream was closed while waited for, or polling failed.SelectableInterface– An object that can be asked whether using it would block, and waited for until it would not.TimeoutException– A wait with a timeout ran out before it was satisfied.
Cancellation and cleanup#
Cancel a coroutine, interrupt its wait, and run code when it ends.
- Introduction
- Examples – Every example in this topic, with its output.
phasync::finally– Registers $fn to run when the current coroutine ends, or when the nested run() it is in returns.phasync::cancel– Cancels a coroutine with a CancelledException.phasync::throw– Interrupts the wait of a suspended coroutine with $exception, once.phasync::signal– Suspends the current coroutine until one of $signals (POSIX signal numbers such as SIGTERM) arrives, and returns the one that did. Any number of coroutines may wait for the same signal: each is woken. The waiter runs as an ordinary coroutine afterwards, so it may await, write and close connections; the signal's handler only records it, and the event loop wakes the waiters between coroutines, never inside one. A signal that came before the wait began doesn't end it.phasync::onSignal– Run $handler the moment $signo arrives, inside the signal handler: with pcntl_async_signals(true) in the middle of whatever is executing, even a coroutine that never yields; otherwise when the event loop dispatches signals. For what must happen at that moment, such as logging where a stuck process is; it must not suspend (no await, sleep or phasync I/O). Coroutines in phasync::signal are woken for the same signal as well. phasync takes the signal over until the outermost phasync::run() returns (a previous pcntl_signal() handler is called as well, and put back then), so register it for a run.phasync::shutdown– Stop the program's coroutines: every coroutine but the caller, whatever frame it is in, gets $exception (a ShutdownException, which is a CancelledException) at its wait, as phasync::cancel() does, and has up to $window seconds to clean up: finally blocks, and phasync::finally() callbacks, which may wait. Returns how many are still running after that, for the caller to decide (for example to exit, dropping them).phasync::shielded– Run $fn out of every cancellation's reach: phasync::cancel(), Frame::cancel(), and phasync::shutdown() don't cut its waits short. A cancellation that comes meanwhile applies at the coroutine's first wait after $fn returns. For infrastructure that must finish what it started, such as a server ending a protocol cleanly while the application's coroutines stop; application code rarely needs it.CancelledException– Thrown in a coroutine whose wait was cancelled: with phasync::cancel(), or with its frame (Frame::cancel(), the frame's deadline, a deadlock).ShutdownException– Thrown into the coroutines of a run by phasync::shutdown(): the program is stopping. It is a CancelledException, so it behaves like one: the coroutine meets it at its wait, its finally blocks run, and cleanup that must wait belongs in phasync::finally(). Code that only needs to stop catches nothing, or CancelledException; code that must tell someone why catches this.
Scopes and frames#
Which operation code belongs to (a Scope), and which run() owns its coroutines (a Frame).
- Introduction
- Examples – Every example in this topic, with its output.
phasync::onScopeChange– Registers $fn to be called when the current Scope changes as the event loop switches coroutines.phasync::frame– Returns the frame of the running coroutine: that of the innermost run() it is in.Frame– The lifetime of a phasync::run() call: the coroutines started inside it, which it waits for, cancels and rethrows.
Channels and messaging#
Pass values between coroutines: channels, queues and publishers.
- Introduction
- Channels – Pass values between coroutines.
- Examples – Every example in this topic, with its output.
phasync::channel– Creates a channel and returns its two ends in $read and $write.phasync::publisher– Creates a publisher: what is written to $publisher is delivered to every subscription of $subscribers.ChannelException– A channel operation failed: it was written to after it was closed, or the wait looked like a deadlock.ReadChannelInterface– The reading end of a channel: values written to the channel arrive here in the order they were written.SubscriberInterface– A subscription to a publisher: a reading end that receives every message published after it was made.SubscribersInterface– The subscription point of a publisher: each call to subscribe() makes a reader that receives every later message.Queue– A first-in first-out queue whose operations take a lock, so coroutines may share it.QueueInterface– A first-in first-out queue that coroutines may share.WriteChannelInterface– The writing end of a channel: write() sends a value to the readers of the channel.
Coordination and limits#
Wait for a group, take a lock, limit a rate, share an event.
- Introduction
- WaitGroup – Wait for a group of coroutines.
- RateLimiter – Limit how often something happens.
- Examples – Every example in this topic, with its output.
Event– A list of listeners that are called when the event is triggered.LockInterface– An object that runs a closure while holding a lock that other coroutines wait for.LockTrait– Implements LockInterface: a lock that is reentrant for the coroutine holding it and fair for the others.RateLimiter– Lets events pass at a fixed rate, shared by every coroutine that calls wait().Synchronized– A mutex for coroutines, identified by a string or an object: only one coroutine at a time runs a closure for the same token.WaitGroup– Waits until a counted amount of work has been done, like Go's sync.WaitGroup.
Resource management#
Limited resources shared by many coroutines: pools and bounded caches.
- Introduction
- Caching: memoization – A cache of a pure function can be shared by every request, if it is bounded.
- Examples – Every example in this topic, with its output.
LruCache– A bounded in-memory cache that forgets the least recently used entries first.Pool– A pool of interchangeable resources, of which only so many may exist at once.
Streams and files#
PSR-7 streams, multipart bodies, and file functions that let others run.
- Introduction
- Examples – Every example in this topic, with its output.
DeadmanException– The writer of a StringBuffer exited without ending it: a read throws this once the buffered data is read.BufferedStream– A seekable PSR-7 stream for a body that is still being produced, kept in memory and then in a temporary file.StringStream– A readable, seekable PSR-7 stream over a string that is known in full.UnbufferedStream– A PSR-7 stream for a body that is still being produced, read once and in order.UploadedFile– A PSR-7 file uploaded with a request.StringBuffer– A buffer of streamed bytes that one coroutine fills and another reads, for parsing protocols that arrive in frames.MultipartStream– A multipart/form-data request body built from a nested array of fields.MultipartStreamInterface– A request body stream that carries a multipart/form-data payload.
HTTP client#
A PSR-18 client on curl_multi, with PSR-7 requests, responses and URIs.
- Introduction
- Concurrent API calls – Call several APIs at once and wait for all of them.
- Examples – Every example in this topic, with its output.
Request– A PSR-7 outgoing, client-side request.Response– A PSR-7 response.ServerRequest– A PSR-7 request as a server received it.Uri– A PSR-7 URI.ClientException– A request failed for a reason that is neither an invalid request nor a network failure.CurlResponse– The PSR-7 response of an HttpClient request, filled in by a cURL transfer.HttpClient– A PSR-18 HTTP client that runs concurrent requests on curl_multi.HttpClientOptions– The options of an HTTP request, as public properties that map to cURL options.NetworkException– No response arrived, or the response stopped arriving, because of a network failure.RequestException– The request could not be sent because it is invalid.
Processes#
Run child processes without blocking the other coroutines.
- Introduction
- Running processes – Run external programs without blocking a worker.
- Examples – Every example in this topic, with its output.
Process– Starts a child process whose standard streams are used from coroutines without blocking the others.ProcessInterface– A child process started with Process::run(), with its standard streams usable from coroutines.ProcessRunner– The implementation behind Process::run(): starts a child process and controls it.
Console and logging#
Styled terminal output and a PSR-3 logger on top of it.
- Introduction
- Examples – Every example in this topic, with its output.
Console– Terminal output from markup: styled on a terminal, plain text when piped to a file, and laid out the same way in both.ConsoleLogger– A PSR-3 logger writing Console::log() lines: to a terminal styled, piped plain.
Blocking calls and the extension#
Which blocking calls become cooperative and the drop-in functions.
- Introduction
- The phasync extension – The optional extension: blocking I/O in existing code suspends the coroutine, not the process.
- Examples – Every example in this topic, with its output.
CurlAwaiter– Runs cURL handles cooperatively, so other coroutines run while a request is in flight.MySQLiAwaiter– Waits for a mysqli asynchronous query without blocking other coroutines.ensure_loaded– Ensure the phasync extension is loaded, re-executing this CLI process with -d extension=<matching .so> if it is not.file_get_contents– Reads a whole file, letting other coroutines run while it waits.file_put_contents– Writes a file, letting other coroutines run while it waits.flock– Locks a file, letting other coroutines run while it waits for the lock.sleep– Suspends the current coroutine for $seconds seconds, letting the others run.
The event loop#
The loop beneath the coroutines, for library authors.
- Introduction
- Internals – The event loop, the pollers and the scheduler.
- Use phasync in a library – Write concurrent library code that runs anywhere PHP runs.
- Examples – Every example in this topic, with its output.
phasync::service– Starts $fn as a service: a coroutine of no frame, in the root scope, which outlives the code that started it, and returns it.phasync::isRunning– Returns true while a phasync::run is in progress, and false otherwise.phasync::getLoop– Returns the event loop, for code that waits with its low-level API (getSlot(), park() and unpark() of the returned object), or drives it in place (tick()).phasync::getFiber– Returns the running coroutine.DeadlockException– Coroutines wait, and nothing can ever wake them: the outermost run() throws this.PollerInterface– Waits for streams on behalf of the event loop.