A non-blocking concurrency framework for PHP applications. 🐘

Overview
Amp Logo

Amp

Amp is a non-blocking concurrency framework for PHP. It provides an event loop, promises and streams as a base for asynchronous programming.

Promises in combination with generators are used to build coroutines, which allow writing asynchronous code just like synchronous code, without any callbacks.

Motivation

Traditionally, PHP has a synchronous execution flow, doing one thing at a time. If you query a database, you send the query and wait for the response from the database server in a blocking manner. Once you have the response, you can start doing the next thing.

Instead of sitting there and doing nothing while waiting, we could already send the next database query, or do an HTTP call to an API.

Making use of the time we usually spend on waiting for I/O can speed up the total execution time. The following diagram shows the execution flow with dependencies between the different tasks, once executed sequentially and once concurrently.

Amp allows such concurrent I/O operations while keeping the cognitive load low by avoiding callbacks. Instead, the results of asynchronous operations can be awaited using yield resulting in code which is structured like traditional blocking I/O code while the actual execution flow is handled by Amp.

Installation

This package can be installed as a Composer dependency.

composer require amphp/amp

This installs the basic building blocks for asynchronous applications in PHP. We offer a lot of repositories building on top of this repository, e.g.

Documentation

Documentation can be found on amphp.org as well as in the ./docs directory. Each packages has it's own ./docs directory.

Requirements

This package requires PHP 7.0 or later. Many of the other packages raised their requirement to PHP 7.1. No extensions required!

Optional Extensions

Extensions are only needed if your app necessitates a high numbers of concurrent socket connections, usually this limit is configured up to 1024 file descriptors.

Examples

Examples can be found in the ./examples directory of this repository as well as in the ./examples directory of our other libraries.

Versioning

amphp/amp follows the semver semantic versioning specification like all other amphp packages.

2.x

Supported. We don't have plans to release v3, yet.

1.x

No longer supported. We stopped providing bug fixes 2017-12-31 and stopped providing security fixes 2018-12-31.

Compatible Packages

Compatible packages should use the amphp topic on GitHub.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

The MIT License (MIT). Please see LICENSE for more information.

Comments
  • Amp v3 with ext-fiber support

    Amp v3 with ext-fiber support

    The author and ext-async extension disappeared for unknown reasons https://github.com/concurrent-php/ext-async, which is very sad.

    Thanks to others, the fork is available: https://github.com/dreamsxin/ext-async

    @kelunik is there still a plan to implement the 3rd version with ext-async support? Here are some mentions about 3rd version plans:

    1. https://github.com/amphp/amp/issues/253#issuecomment-449875440
    2. https://github.com/amphp/amp/issues/229#issuecomment-448705155

    Thanks!

    question discussion v3.x 
    opened by dbalabka 35
  • Version 2 Review

    Version 2 Review

    @trowski @bwoebi @rdlowrey I reviewed Amp v2.0 and here are my comments.

    Internal\WhenQueue

    How important is the layer of indirection? If we're worried about the call stack, should we instead resolve promises asynchronously?

    It could also be renamed to a more generic name like CallbackQueue or CallQueue.

    Internal\Placeholder

    Annotation for $onResolved is callable|\Amp\Internal\WhenQueue|null, should be ?WhenQueue or ?WhenQueue|null instead.

    Coroutine

    Why does it not accept a callable as constructor parameter in addition of generators?

    Emitter

    if ($this->resolved) {
        return;
    }
    

    ^ Does that ignore double resolution silently?

    Pause

    Do we really need $value there? What about keep_alive = false?

    Internal\LazyPromise

    Why is this one internal? Why is Amp\lazy suggested to be used only? Why do we even have Amp\lazy? Instead of using arguments to Amp\lazy, those parameters can just be use'd in a closure by the user instead of providing them as arguments.

    Amp\wrap vs. Amp\coroutine

    It is weird to have both and usage will be confusion for users.

    Amp\timeout

    I think Amp\timeout shouldn't keep the loop running. The watchers should probably be unreferenced.

    Amp\lift

    Do we need lift? I always ask that when reading the docs regarding it.

    Amp\filter

    Amp\filter filters observables now instead of promises.

    opened by kelunik 25
  • Support for Guzzle / generic promise adaption

    Support for Guzzle / generic promise adaption

    Guzzle promises implement A+ promises but are no react promises. How about supporting them as well or more generic all vendor-promises that implement "then()"? Instead of $result instanceof ReactPromise you would write e.g. isVendorPromise($result). adapt() handles any object that implements done() or then() anyway.

    Any opinions?

    feature request 
    opened by brstgt 24
  • Changing

    Changing "when" to "onResolve" or "onComplete"

    It doesn't matter for normal promises, but I think it matters for more advanced use cases where the promise API is just one way of consumption. Looking at a list of functions, onResolve / onComplete are way more expressive than when.

    change request discussion 
    opened by kelunik 20
  • Promise\wait together with Promise\rethrow

    Promise\wait together with Promise\rethrow

    (copied from irc)

    hi folks php: src/unix/core.c:896: uv__io_stop: Assertion `loop->watchers[w->fd] == w' failed. what does that tell me?

    this happened to me once I added some new tests today but it appeared on old tests so I encounter this only when running the whole test-suite I switched to EV and the problem disappeared seems to be a bug in UV ?

    I wrote 2 new test classes today, one results in to uv error above, which I can prevent by switching to ev the second one makes a bunch of old tests red, when I start the whole test-suite, but they will all be green again, when I exclude this one so weird

    mmh... seems to have something to do with using wait(call(...)) within the tests, and inside the lib I do Promise\rethrow($subscription->start()); somewhere when I don't to the rethrow thing, then the other tests are green again

    I can make the tests pass with a different Promise\wait implementation check this out please

    function wait($promise) {
            if (!$promise instanceof Promise) {
                if ($promise instanceof ReactPromise) {
                    $promise = adapt($promise);
                } else {
                    throw createTypeError([Promise::class, ReactPromise::class], $promise);
                }
            }
    
            $resolved = false;
            $wait = true;
            $exception = null;
            $value = null;
    
            $promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception, &$wait) {
                $resolved = true;
                $exception = $e;
                $value = $v;
                $wait = false;
                Loop::stop();
            });
    
            while($wait) {
                Loop::run();
            }
    
            if ($exception) {
                throw $exception;
            }
    
            return $value;
        }
    

    but uv still is a problem

    question 
    opened by prolic 17
  • Make resolve() accept also callables

    Make resolve() accept also callables

    This is just syntactic sugar around resolve() for use with a generator closure to avoid temporary variables.

    Instead of having to write:

    $var = function() {
        yield;
    };
    return resolve($var);
    

    you can simply write:

    return promise(function() {
        yield;
    });
    

    I'm not married to the function name if it doesn't suit, but this is an option I have found frustratingly missing.

    This PR also adds a missing @return tag to the resolve() docblock.

    opened by DaveRandom 17
  • Async programming with blocking operations

    Async programming with blocking operations

    Hi,

    I am trying to figure out how to get some blocking tasks performed in parallel, the example is here:

    https://gist.github.com/yoanisgil/a28d57abca781fd84af1

    Roughly the script will launch 5 asynchronous tasks (asyncMultiply) each of which will perform a random sleep. When I run the script with:

    time docker run -v $(PWD):/usr/src/myapp  -ti --rm yoanisgil/php56-cli-composer php test.php
    

    it takes about ~ 16 secs, which indicates that tasks are performed synchronously (each task performs a random sleep between 2 - 4 seconds).

    Given the deferred/asynchronous nature of promises and that I'm using Amp\immediately I would have expected about ~ 4 seconds of execution.

    For sure I most be doing something wrong. Any ideas what that might be?

    Bests,

    Yoanis.

    opened by yoanisgil 17
  • Getting access to child process data on SIGCHLD in Loop::onSignal.

    Getting access to child process data on SIGCHLD in Loop::onSignal.

    I'm playing around with launching processes in a fiber, suspending the fiber and then restarting the fiber to collect results on SIGCHLD signal based on the child pid/exit code in pcntl_signal(SIGCHLD, ... ).

    I don't see a way to access the terminating child PID in Loop::onSignal() however. Is it possible? It would be a nice feature to have otherwise.

    With the event loop I'm now resuming all fibers on SIGCHLD in Loop::onSignal and suspending them again immediately inside the fiber.

    question 
    opened by whataboutpereira 16
  • Question: Does yield always wait?

    Question: Does yield always wait?

    Does yield always wait until all yielded commands are finished? Or is it possible to yield and continue running the function while the yielded command runs concurrently?

    opened by olleharstedt 16
  • Doing async job while sending http request

    Doing async job while sending http request

    Hi there! I am trying to understand whether it is possible to do some async job while sending async http request in the same Loop of the same php process.

    My goal is to iterate over a long array and filter it by "evaluating" each item (time & cpu consuming op). Filtered items contain a url that should be requested. But to avoid awaiting for response I could continue iterating meanwhile. I've tried using producer/consumer pattern but "yield $client->request()" blocks everything. Is there a way of handling such task?

    opened by proArtex 16
  • Add more generic phpdocs

    Add more generic phpdocs

    See #305

    This allows:

    interface WatcherProcess
    {
        public function stop(): void;
    
        /**
         * @return Promise<?ModifiedFile>
         */
        public function wait(): Promise;
    }
    
    opened by dantleech 16
  • Migration guide for combinator functions

    Migration guide for combinator functions

    Owing to the fact that v2's Promise\any would accept an empty array, its v3 analogue awaitAny should do the same, but it does not; it requires at least one element in the iterable collection otherwise it throws:

    In functions.php line 91: [Amp\CompositeLengthException]
    Argument #2 ($futures) contains too few futures to satisfy the required count of 1

    Due to this, we need to remember to guard against the empty array case when migrating, which is error prone.

    documentation v3.x 
    opened by Bilge 4
  • UnhandledFutureError is hard to debug

    UnhandledFutureError is hard to debug

    Currently, we don't offer good / any debugging tools to debug and fix unhandled future errors. This makes them annoying and very hard to find and fix.

    change request v3.x 
    opened by kelunik 1
  • QUIC support

    QUIC support

    Hello,

    My point of view on amphp is that this project pushes always PHP limits further, and I love it. I think it's time to talk about a support of QUIC so amp can support HTTP/3 as well.

    For the record, QUIC is already supported in some languages, see Wikipedia: https://en.wikipedia.org/wiki/QUIC#Source_code

    What do you think about that? Do you have any plan for its support? I assume it should be a package on top of the UDP library of amp.

    feature request 
    opened by Nek- 2
  • EvLoop::io(): 9 bytes of buffered data lost during stream conversion!

    EvLoop::io(): 9 bytes of buffered data lost during stream conversion!

    EvLoop::io(): 9 bytes of buffered data lost during stream conversion!, /home/shared/vendor/amphp/amp/lib/Loop/EvDriver.php:253
    
    $ pecl list
    Installed packages, channel pecl.php.net:
    =========================================
    Package Version State
    ev      1.1.2   stable
    pq      2.1.8   stable
    raphf   2.0.1   stable
    
    opened by PNixx 8
Releases(v3.0.0-beta.10)
  • v3.0.0-beta.10(Nov 7, 2022)

    What's Changed

    • Allow GC of arguments during async() closure execution (https://github.com/amphp/amp/pull/395)
    • Support revolt 1.x, declare incompatibility with revolt 0.1.x
    • Change Future::ignore() to be a fluent interface (https://github.com/amphp/amp/pull/403)
    • Improve template types

    Full Changelog: https://github.com/amphp/amp/compare/v3.0.0-beta.9...v3.0.0-beta.10

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.9(Jul 12, 2022)

    • Fixed circular reference in async() on exceptions (https://github.com/amphp/amp/issues/394)
    • Removed deprecated combinator functions:
      • Amp\Future\race β†’ Amp\Future\awaitFirst
      • Amp\Future\any β†’ Amp\Future\awaitAny
      • Amp\Future\some β†’ Amp\Future\awaitAnyN
      • Amp\Future\settle β†’ Amp\Future\awaitAll
      • Amp\Future\all β†’ Amp\Future\await
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.8(Jun 25, 2022)

    • Fixed weakClosure() not preserving scope when using a Closure with scope limited to a parent class (#393)
    • Fixed regression in beta 9 where CompositeCancellation would return false from isRequested() and not throw from throwIfRequested() after cancellation was requested
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.7(Jun 16, 2022)

    • Added SignalCancellation that triggers a cancellation when a particular signal is received by the process.
    • Fixed an issue in CombinedCancellation where subsequent cancellation of another Cancellation in the set could alter the exception used to cancel the token.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.6(Apr 23, 2022)

  • v3.0.0-beta.5(Apr 3, 2022)

    • Added Closable interface for closable resources such as streams (the interface of the same name will be removed from amphp/byte-stream in a future release) (#387)
    Source code(tar.gz)
    Source code(zip)
  • v2.6.2(Feb 20, 2022)

  • v3.0.0-beta.4(Jan 16, 2022)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    • Mark Future template parameter as covariant
    • Add compatibility with revolt/event-loop v0.2.x
    • Improve exception message of UnhandledFutureError
    • Cancel DeferredCancellation when destroyed (#382)
    • Rename combinators, introduce CompositeLengthException (#383)
      • race β†’ awaitFirst
      • any β†’ awaitAny
      • some β†’ awaitAnyN
      • settle β†’ awaitAll
      • all β†’ await
      • The old names have been kept for a migration phase, but will be removed before the final v3 release.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.3(Dec 22, 2021)

  • v3.0.0-beta.2(Dec 3, 2021)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    • Fixed revolt/event-loop dependency declaration to use released ^0.1 version.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.1(Dec 3, 2021)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    Event Loop

    Amp no longer ships its own event loop. It's now based on Revolt. Revolt\EventLoop is quite similar to Amp's previous Amp\Loop. A very important difference is using float $seconds instead of int $milliseconds for timers.

    Futures

    Future is a replacement for the previous Promise. It's await() method is based on fibers and replaces generator based coroutines / Amp\Promise\wait().

    • await() accepts an optional Cancellation, which can be used as a replacement for Amp\Promise\timeout().
    • Unhandled errors are now automatically thrown into the event loop, so there's no need for Amp\Promise\rethrow() anymore.
    • Unhandled errors can be ignored using Future::ignore().

    Cancellation

    • CancellationToken has been renamed to Cancellation
    • CancellationTokenSource has been renamed to DeferredCancellation
    • NullCancellationToken has been renamed to NullCancellation
    • TimeoutCancellationToken has been renamed to TimeoutCancellation
    • CombinedCancellationToken has been renamed to CompositeCancellation
    Source code(tar.gz)
    Source code(zip)
  • v2.6.1(Sep 23, 2021)

    • Fixed destructor issue in EventDriver (#358)
    • Fixed EventDriver feature configuration to work with different kinds of FDs, e.g. under certain conditions in docker containers (#360)
    Source code(tar.gz)
    Source code(zip)
  • v2.6.0(Jul 16, 2021)

  • v2.5.2(Jan 10, 2021)

    • Ignore only stream_select errors due to signal interruptions (#338) Fixes stream_select handling on signal interruptions on PHP 8 and avoids suppressing errors that shouldn't be suppressed.
    • Improve type definition for combinators (any, first, some) (#334)
    • Removed internal `TimerQueueEntry
    Source code(tar.gz)
    Source code(zip)
  • v2.5.1(Nov 3, 2020)

    • Fixed issue where cancelling timer watchers in NativeDriver could result in timers being executed out of order (#332)
    • Fixed 100% CPU usage in NativeDriver when only signal watchers were enabled
    Source code(tar.gz)
    Source code(zip)
  • v2.5.0(Jul 14, 2020)

    • Add Amp\Iterator\discard() (#315)
    • Fix potential warning on shutdown in UvDriver
    • Fix repeat watchers in NativeDriver that are disabled and re-enabled during callback invocation (#325)
    • Fix timer intervals being counted from timer creation instead of last tick time (#319)
    • Loop::now() / Driver::now() is no longer cached in each tick
    Source code(tar.gz)
    Source code(zip)
  • v2.4.4(Apr 30, 2020)

    • Fixed Delayed::reference() / Delayed::unreference() after the promise resolved
    • Changed return type of Delayed::reference() / Delayed::unreference() to self to allow fluid API usage
    • Add generics for Amp\Promise\wait
    • Improved types for Amp\call / Amp\coroutine
    Source code(tar.gz)
    Source code(zip)
  • v2.4.3(Apr 19, 2020)

  • v2.4.2(Apr 4, 2020)

    • Provide useful exception trace in TimeoutCancellationToken (#303)
    • Add parameter for custom timeout message (#299)
    • Add psalm annotations for improved static analysis
    Source code(tar.gz)
    Source code(zip)
  • v2.4.1(Feb 13, 2020)

  • v2.4.0(Nov 11, 2019)

    • Added getCurrentTime() as public API, providing millisecond timestamps for runtime measurements with special support for 32 bit systems. Returned timestamps are relative to an arbitrary point in time, so this API is only suitable to compare two timestamps generated in the same process.
    Source code(tar.gz)
    Source code(zip)
  • v2.3.2(Oct 26, 2019)

  • v2.3.1(Oct 1, 2019)

  • v2.3.0(Oct 1, 2019)

    • Added TracingDriver to debug (hanging) tests / applications. The environment variable AMP_DEBUG_TRACE_WATCHERS=true can be set to automatically create a TracingDriver wrapping the actual driver. TracingDriver::dump() can be used to dump all enabled, referenced watchers keeping the loop running.
    Source code(tar.gz)
    Source code(zip)
  • v2.2.1(Sep 21, 2019)

    • Fixed backpressure release on Emitter::emit(), the backpressure is now released as soon as the value is consumed, instead of the next value being requested.
    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Aug 2, 2019)

  • v2.1.2(Jun 10, 2019)

    • Fixed issue where the loop time in NativeDriver was not refreshed after waiting for I/O streams (#256)
    • Fixed compatibility issue of NativeDriver with pcntl_async_signals() (#264)
    • A custom queue is now used for timers in NativeDriver to allow cancelled timers to be garbage collected immediately instead of after their original expiration time (#220)
    • Resolving a promise with an object that throws when destructed will now forward that exception to the event loop error handler (#271)
    • Fixed loop time to support 32-bit systems (#252, #273)
    Source code(tar.gz)
    Source code(zip)
  • v2.1.1(Dec 11, 2018)

  • v2.1.0(Dec 10, 2018)

    • Make use of hrtime() as monotonic time source if available (PHP 7.3)
    • Added Amp\Iterator\toArray()
    • Added Amp\Promise\timeoutWithDefault() (#245)
    • Added Amp\Promise\wrap() (#234)
    • Added Amp\Loop::now()
    • Fixed stale NativeDriver::$now values (#243)
    Source code(tar.gz)
    Source code(zip)
  • v2.0.7(Apr 30, 2018)

    • Fixed recording of stack traces for double resolution in case AMP_DEBUG was not set as environment variable, defaulting to 0 now. (#217)
    • Loop::unreference() is ignored on invalid watchers now.
    • Invoke UV watchers in case no events or UV_DISCONNECT is indicated.
    • Ignore Loop::$driver not being set during shutdown, which might happen due to the unreliable shutdown order. (#212)
    Source code(tar.gz)
    Source code(zip)
Owner
Amp
Asynchronous Multitasking PHP
Amp
Promises/A implementation for PHP.

Promise A lightweight implementation of CommonJS Promises/A for PHP. The master branch contains the code for the upcoming 3.0 release. For the code of

ReactPHP 2.2k Dec 1, 2022
Promises/A+ library for PHP with synchronous support

Guzzle Promises Promises/A+ implementation that handles promise chaining and resolution iteratively, allowing for "infinite" promise chaining while ke

Guzzle 7.3k Nov 27, 2022
A non-blocking concurrency framework for PHP applications. 🐘

Amp is a non-blocking concurrency framework for PHP. It provides an event loop, promises and streams as a base for asynchronous programming. Promises

Amp 3.8k Dec 3, 2022
Event-driven, non-blocking I/O with PHP.

Event-driven, non-blocking I/O with PHP. ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of

ReactPHP 8.5k Dec 7, 2022
Event-driven, non-blocking I/O with PHP.

Event-driven, non-blocking I/O with PHP. ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of

ReactPHP 8.5k Dec 4, 2022
A non-blocking stream abstraction for PHP based on Amp.

amphp/byte-stream is a stream abstraction to make working with non-blocking I/O simple. Installation This package can be installed as a Composer depen

Amp 316 Dec 2, 2022
A simple RESTful non-blocking API, to send and receive money

A simple RESTful non-blocking API, to send and receive money.

Daniel Rodrigues 2 Apr 1, 2022
πŸš€ Coroutine-based concurrency library for PHP

English | δΈ­ζ–‡ Swoole is an event-driven asynchronous & coroutine-based concurrency networking communication engine with high performance written in C++

Swoole Project 17.6k Nov 25, 2022
πŸš€ Coroutine-based concurrency library for PHP

English | δΈ­ζ–‡ Swoole is an event-driven asynchronous & coroutine-based concurrency networking communication engine with high performance written in C++

Swoole Project 17.6k Nov 30, 2022
PHP application-level database locking mechanisms to implement concurrency control patterns.

PHP DB Locker Introduction PHP application-level database locking mechanisms to implement concurrency control patterns. Supported drivers: Postgres In

cybercog 3 Sep 29, 2022
Examples of using each Illuminate component in non-Laravel applications

Torch - Using Laravel's Illuminate Components Independently Torch is a project to provide instructions and examples for using Illuminate components as

Matt Stauffer 1.7k Nov 30, 2022
Laravel Ban simplify blocking and banning Eloquent models.

Laravel Ban Introduction Laravel Ban simplify management of Eloquent model's ban. Make any model bannable in a minutes! Use case is not limited to Use

cybercog 866 Nov 29, 2022
Eloquent Befriended brings social media-like features like following, blocking and filtering content based on following or blocked models.

Laravel Befriended Eloquent Befriended brings social media-like features like following, blocking and filtering content based on following or blocked

Renoki Co. 715 Nov 13, 2022
Enables auto-blocking of NFT artists and cryptobros on Twitter.

NFT Artist & Cryptobro blocker for Twitter Enables auto-blocking of NFT artists and cryptobros on Twitter. You can block a list of NFT artists and als

Ant 72 Nov 3, 2022
Laravel Nova Ban simplify blocking and banning Eloquent models.

Laravel Nova Ban Introduction Behind the scenes cybercog/laravel-ban is used. Contents Installation Usage Prepare bannable model Prepare bannable mode

cybercog 39 Sep 29, 2022
Lightweight library that eases using components built for ReactPHP in a traditional, blocking environment.

clue/reactphp-block Lightweight library that eases integrating async components built for ReactPHP in a traditional, blocking environment. ReactPHP pr

Christian LΓΌck 154 Sep 10, 2022
Barcode generator in PHP that is easy to use, non-bloated and framework independent.

PHP Barcode Generator This is an easy to use, non-bloated, framework independent, barcode generator in PHP. It creates SVG, PNG, JPG and HTML images,

Picqer 1.4k Dec 5, 2022
Rori-PHP is custom non production web application framework inspired by Laravel syntax

Rori-PHP is custom non production web application framework inspired by Laravel syntax. A web framework provides a structure and starting point for your application allowing you to focus on creating something amazing.

UnknownRori 5 Jul 28, 2022
A fast PHP slug generator and transliteration library that converts non-ascii characters for use in URLs.

URLify for PHP A fast PHP slug generator and transliteration library, started as a PHP port of URLify.js from the Django project. Handles symbols from

Aband*nthecar 664 Nov 28, 2022
Deploy and execute non-PHP AWS Lambda functions from your Laravel application.

Sidecar for Laravel Deploy and execute non-PHP AWS Lambda functions from your Laravel application. Read the full docs at hammerstone.dev/sidecar/docs.

Hammerstone 612 Nov 26, 2022