phasync
phasync / Manual

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.