PHPackages                             amphp/sync - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. amphp/sync

ActiveLibrary[Queues &amp; Workers](/categories/queues)

amphp/sync
==========

Non-blocking synchronization primitives for PHP based on Amp and Revolt.

v2.3.0(1y ago)19052.8M—5.1%1220MITPHPPHP &gt;=8.1CI failing

Since Nov 29Pushed 1mo ago6 watchersCompare

[ Source](https://github.com/amphp/sync)[ Packagist](https://packagist.org/packages/amphp/sync)[ Docs](https://github.com/amphp/sync)[ GitHub Sponsors](https://github.com/amphp)[ RSS](/packages/amphp-sync/feed)WikiDiscussions 2.x Synced 1mo ago

READMEChangelog (10)Dependencies (8)Versions (20)Used By (20)

amphp/sync
==========

[](#amphpsync)

AMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind. `amphp/sync` specifically provides synchronization primitives such as locks and semaphores for asynchronous and concurrent programming.

[![Latest Release](https://camo.githubusercontent.com/4c16c7dc75a163a505bfb4b813467ab27de2f5a9e0f7af00e664dc20fc3ec1f7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f616d7068702f73796e632e7376673f7374796c653d666c61742d737175617265)](https://github.com/amphp/sync/releases)[![MIT License](https://camo.githubusercontent.com/942e017bf0672002dd32a857c95d66f28c5900ab541838c6c664442516309c8a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d666c61742d737175617265)](https://github.com/amphp/sync/blob/master/LICENSE)

Installation
------------

[](#installation)

This package can be installed as a [Composer](https://getcomposer.org/) dependency.

```
composer require amphp/sync
```

Usage
-----

[](#usage)

The weak link when managing concurrency is humans; so `amphp/sync` provides abstractions to hide some complexity.

### Mutex

[](#mutex)

[Mutual exclusion](https://en.wikipedia.org/wiki/Mutual_exclusion) can be achieved using `Amp\Sync\synchronized()` and any `Mutex` implementation, or by manually using the `Mutex` instance to acquire a `Lock`.

As long as the resulting `Lock` object isn't released using `Lock::release()` or by being garbage collected, the holder of the lock can exclusively run some code as long as all other parties running the same code also acquire a lock before doing so.

```
function writeExclusively(Amp\Sync\Mutex $mutex, string $filePath, string $data) {
    $lock = $mutex->acquire();

    try {
        Amp\File\write($filePath, $data);
    } finally {
        $lock->release();
    }
}
```

```
function writeExclusively(Amp\Sync\Mutex $mutex, string $filePath, string $data) {
    Amp\Sync\synchronized($mutex, fn () => Amp\File\write($filePath, $data));
}
```

### Semaphore

[](#semaphore)

[Semaphores](https://en.wikipedia.org/wiki/Semaphore_%28programming%29) are another synchronization primitive in addition to [mutual exclusion](#mutex).

Instead of providing exclusive access to a single party, they provide access to a limited set of N parties at the same time. This makes them great to control concurrency, e.g. limiting an HTTP client to X concurrent requests, so the HTTP server doesn't get overwhelmed.

Similar to [`Mutex`](#mutex), `Lock` instances can be acquired using `Semaphore::acquire()`. Please refer to the [`Mutex`](#mutex) documentation for additional usage documentation, as they're basically equivalent except for the fact that `Mutex` is always a `Semaphore` with a count of exactly one party.

In many cases you can use [`amphp/pipeline`](https://github.com/amphp/pipeline) instead of directly using a `Semaphore`.

### Parcel

[](#parcel)

A Parcel is used to synchronize access to a value across multiple execution contexts, such as multiple coroutines or multiple processes. The example below demonstrates using a `LocalParcel` to share an integer between two coroutines.

```
use Amp\Future;
use Amp\Sync\LocalMutex;
use Amp\Sync\LocalParcel;
use function Amp\async;
use function Amp\delay;

$parcel = new LocalParcel(new LocalMutex(), 42);

$future1 = async(function () use ($parcel): void {
    echo "Coroutine 1 started\n";

    $result = $parcel->synchronized(function (int $value): int {
        delay(1); // Delay for 1s to simulate I/O.
        return $value * 2;
    });

    echo "Value after access in coroutine 1: ", $result, "\n";
});

$future2 = async(function () use ($parcel): void {
    echo "Coroutine 2 started\n";

    $result = $parcel->synchronized(function (int $value): int {
        delay(1); // Delay again in this coroutine.
        return $value + 8;
    });

    echo "Value after access in coroutine 2: ", $result, "\n";
});

Future\await([$future1, $future2]); // Wait until both coroutines complete.
```

### Channels

[](#channels)

Channels are used to send data between execution contexts, such as multiple coroutines or multiple processes. The example below shares two `Channel` between two coroutines. These channels are connected. Data sent on a channel is received on the paired channel and vice-versa.

```
use Amp\Future;
use function Amp\async;
use function Amp\delay;

[$left, $right] = createChannelPair();

$future1 = async(function () use ($left): void {
    echo "Coroutine 1 started\n";
    delay(1); // Delay to simulate I/O.
    $left->send(42);
    $received = $left->receive();
    echo "Received ", $received, " in coroutine 1\n";
});

$future2 = async(function () use ($right): void {
    echo "Coroutine 2 started\n";
    $received = $right->receive();
    echo "Received ", $received, " in coroutine 2\n";
    delay(1); // Delay to simulate I/O.
    $right->send($received * 2);
});

Future\await([$future1, $future2]); // Wait until both coroutines complete.
```

### Sharing data between processes

[](#sharing-data-between-processes)

To share data between processes in PHP, the data must be serializable and use external storage or an IPC (inter-process communication) channel.

#### Parcels in external storage

[](#parcels-in-external-storage)

`SharedMemoryParcel` uses shared memory conjunction with `PosixSemaphore` wrapped in `SemaphoreMutex` (though another cross-context mutex implementation may be used, such as `RedisMutex` in [`amphp/redis`](https://github.com/amphp/redis)).

> **Note**`ext-shmop` and `ext-sysvmsg` are required for `SharedMemoryParcel` and `PosixSemaphore` respectively.

[`amphp/redis`](https://github.com/amphp/redis) provides `RedisParcel` for storing shared data in Redis.

#### Channels over pipes

[](#channels-over-pipes)

Channels between processes can be created by layering serialization (native PHP serialization, JSON serialization, etc.) on a pipe between those processes.

`StreamChannel` in [`amphp/byte-stream`](https://github.com/amphp/byte-stream) creates a channel from any `ReadableStream` and `WritableStream`. This allows a channel to be created from a variety of stream sources, such as sockets or process pipes.

`ProcessContext` in [`amphp/parallel`](https://github.com/amphp/parallel) implements `Channel` to send data between parent and child processes.

Task `Execution` objects, also in [`amphp/parallel`](https://github.com/amphp/parallel) contain a `Channel` to send data between the task run and the process which submitted the task.

### Concurrency Approaches

[](#concurrency-approaches)

Given you have a list of URLs you want to crawl, let's discuss a few possible approaches. For simplicity, we will assume a `fetch` function already exists, which takes a URL and returns the HTTP status code (which is everything we want to know for these examples).

#### Approach 1: Sequential

[](#approach-1-sequential)

Simple loop using non-blocking I/O, but no concurrency while fetching the individual URLs; starts the second request as soon as the first completed.

```
$urls = [...];

$results = [];

foreach ($urls as $url) {
    $results[$url] = fetch($url);
}

var_dump($results);
```

#### Approach 2: Everything Concurrently

[](#approach-2-everything-concurrently)

Almost the same loop, but awaiting all operations at once; starts all requests immediately. Might not be feasible with too many URLs.

```
$urls = [...];

$results = [];

foreach ($urls as $url) {
    $results[$url] = Amp\async(fetch(...), $url);
}

$results = Amp\Future\await($results);

var_dump($results);
```

#### Approach 3: Concurrent Chunks

[](#approach-3-concurrent-chunks)

Splitting the jobs into chunks of ten; all requests within a chunk are made concurrently, but each chunk sequentially, so the timing for each chunk depends on the slowest response; starts the eleventh request as soon as the first ten requests completed.

```
$urls = [...];

$results = [];

foreach (\array_chunk($urls, 10) as $chunk) {
    $futures = [];

    foreach ($chunk as $url) {
        $futures[$url] = Amp\async(fetch(...), $url);
    }

    $results = \array_merge($results, Amp\Future\await($futures));
}

var_dump($results);
```

#### Approach 4: ConcurrentIterator

[](#approach-4-concurrentiterator)

The [`amphp/pipeline`](https://github.com/amphp/pipeline) library provides concurrent iterators which can be used to process and consume data concurrently in multiple fibers.

```
use Amp\Pipeline\Pipeline;
use function Amp\delay;

$urls = [...];

$results = Pipeline::fromIterable($urls)
    ->concurrent(10) // Process up to 10 URLs concurrently
    ->unordered() // Results may arrive out of order
    ->map(fetch(...)) // Map each URL to fetch(...)
    ->toArray();

var_dump($results);
```

See the documentation in [`amphp/pipeline`](https://github.com/amphp/pipeline) for more information on using Pipelines for concurrency.

Versioning
----------

[](#versioning)

`amphp/sync` follows the [semver](http://semver.org/) semantic versioning specification like all other `amphp` packages.

Security
--------

[](#security)

If you discover any security related issues, please use the private security issue reporter instead of using the public issue tracker.

License
-------

[](#license)

The MIT License (MIT). Please see [`LICENSE`](./LICENSE) for more information.

###  Health Score

67

↑

FairBetter than 100% of packages

Maintenance66

Regular maintenance activity

Popularity68

Solid adoption and visibility

Community37

Small or concentrated contributor base

Maturity81

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 51.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~128 days

Recently: every ~145 days

Total

20

Last Release

653d ago

Major Versions

v1.4.2 → v2.0.0-beta.12021-12-06

PHP version history (3 changes)v1.1.0PHP &gt;=7.1

v2.0.0-beta.1PHP &gt;=8

v2.0.0-beta.4PHP &gt;=8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1628287?v=4)[Aaron Piotrowski](/maintainers/Trowski)[@trowski](https://github.com/trowski)

![](https://www.gravatar.com/avatar/12852217f3369e8144bc9ce6ac2a2341c28c5512c5b3df5749bfbbd45b6877ff?d=identicon)[kelunik](/maintainers/kelunik)

![](https://www.gravatar.com/avatar/f6db63ad594446f67d79532b75c69439fd0df779cc90868b43c187c02a4221ef?d=identicon)[bwoebi](/maintainers/bwoebi)

---

Top Contributors

[![trowski](https://avatars.githubusercontent.com/u/1628287?v=4)](https://github.com/trowski "trowski (94 commits)")[![kelunik](https://avatars.githubusercontent.com/u/2743004?v=4)](https://github.com/kelunik "kelunik (79 commits)")[![enumag](https://avatars.githubusercontent.com/u/539462?v=4)](https://github.com/enumag "enumag (2 commits)")[![iggyvolz](https://avatars.githubusercontent.com/u/2197376?v=4)](https://github.com/iggyvolz "iggyvolz (1 commits)")[![azjezz](https://avatars.githubusercontent.com/u/29315886?v=4)](https://github.com/azjezz "azjezz (1 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (1 commits)")[![prolic](https://avatars.githubusercontent.com/u/394428?v=4)](https://github.com/prolic "prolic (1 commits)")[![rybakit](https://avatars.githubusercontent.com/u/533861?v=4)](https://github.com/rybakit "rybakit (1 commits)")[![thgs](https://avatars.githubusercontent.com/u/8940963?v=4)](https://github.com/thgs "thgs (1 commits)")[![danog](https://avatars.githubusercontent.com/u/7339644?v=4)](https://github.com/danog "danog (1 commits)")[![b1rdex](https://avatars.githubusercontent.com/u/312855?v=4)](https://github.com/b1rdex "b1rdex (1 commits)")

---

Tags

amphpasyncconcurrencymutexphprevoltsemaphoresynchronizationasyncasynchronoussynchronizationsemaphoremutex

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/amphp-sync/health.svg)

```
[![Health](https://phpackages.com/badges/amphp-sync/health.svg)](https://phpackages.com/packages/amphp-sync)
```

###  Alternatives

[amphp/parallel

Parallel processing component for Amp.

85046.2M74](/packages/amphp-parallel)[amphp/amp

A non-blocking concurrency framework for PHP applications.

4.4k123.4M323](/packages/amphp-amp)[amphp/byte-stream

A stream abstraction to make working with non-blocking I/O simple.

393116.2M104](/packages/amphp-byte-stream)[revolt/event-loop

Rock-solid event loop for concurrent PHP applications.

92343.6M138](/packages/revolt-event-loop)[amphp/redis

Efficient asynchronous communication with Redis servers, enabling scalable and responsive data storage and retrieval.

165634.7k44](/packages/amphp-redis)[amphp/socket

Non-blocking socket connection / server implementations based on Amp and Revolt.

26539.0M119](/packages/amphp-socket)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
