Search by

antevemus / alinq-parallel

helitonjr

CPU-parallel companion of antevemus/alinq-collection: selectParallel(), whereParallel(), selectManyParallel() and eachParallel() run per-item work in a pool of worker PHP processes (proc_open, no extension required), through an ordered, bounded, lazy window, returning core ALinq lazy collections

v1.0.0 2026-10-21 16:09 UTC

This package is auto-updated.

Last update: 2026-10-21 16:34:17 UTC


README

CI Latest Stable Version PHP Version License: MIT Tests Passing Core: ALinq

The CPU-parallel companion of ALinq for PHP 8.4+
selectParallel(), whereParallel(), selectManyParallel() and eachParallel() run each item's work in a pool of worker PHP processes (proc_open(), no extension required), through an ordered, bounded, lazy window of items in flight, and the result is a core ALinq lazy collection, so every core operator chains after it. For CPU work per item: parsing, hashing, rendering, computing.

🇺🇸 English • 🇧🇷 Português (Brasil)

The documentation lives in docs/en (English) and docs/pt-BR (Portuguese, Brazil), one page per topic, in the Docs Kit format (a docs-nav.json per language), and every PHP block of the pages is run by the test suite.

🚀 Quick Start

The same block opens Getting Started, which also shows App\Work\Primes, a plain class of the application that the workers load through its Composer autoloader; the test suite runs the block with the answer written in its comments:

<?php

declare(strict_types=1);

use Antevemus\ALinqParallel\ALinqParallelCollection;
use App\Work\Primes;

// Count the primes below each limit, four limits at a time, each in a worker process
$counts = ALinqParallelCollection::from([10_000, 20_000, 30_000, 40_000])
    ->selectParallel([Primes::class, 'countBelow'], workers: 4) // a static method travels by name
    ->where(fn(int $count) => $count > 2000) // the core operators chain after it, in this process
    ->toArray();

// Result: [2262, 3245, 4203]

📦 Installation

Install via Composer: composer require antevemus/alinq-parallel. Requirements: PHP 8.4 or later, with proc_open() enabled; installed with it: antevemus/alinq-collection ^2.3 (the core, same author; 2.3.0 for the declared shape of a generator stage). No PHP extension is required: no pcntl, no posix, no parallel.

The work runs in another process, so it must travel there: a public static method ([Primes::class, 'countBelow'], Primes::countBelow(...)), a function, or a serializable invokable object; an anonymous closure is refused before any process starts, because PHP cannot serialize a Closure. Measured on 12 CPUs loaded by other work (load average 18.6), 16 items of about 200 ms of CPU each: 3 084 ms through the core select(), 1 733 ms through selectParallel(workers: 2), 1 305 ms with 4 workers and 875 ms with 8; 16 trivial items cost 98 to 134 ms through a pool started for the traversal (starting PHP) and about 1 ms through a pool already started, against 0.02 ms through select() (Tests).

📚 Documentation

Getting started

Concepts

  • How it works · pt-BR: Processes, not Fibers; the ordered, bounded, lazy window and early stop; what travels to a worker; when it pays.

API reference

  • Parallel operators · pt-BR: The four operators, the work, keys, errors and crashes, time limits and a shared ProcessPool.

Internals

  • Architecture · pt-BR: Why processes and not ext-parallel or pcntl, the transportable-work contract, the frame protocol, and what a companion for another transport implements.

Quality

  • Tests · pt-BR: The PHPUnit report, the measured timing table and the mutation testing.

Project

  • Roadmap · pt-BR: The release shipped and what comes next; the milestone view is in ROADMAP.md.

🧪 Quality

  • Tests: 219 PHPUnit tests (vendor/bin/phpunit) and 9340 assertions, 100% passing on PHP 8.4: the operators and the pool against real worker processes (crashes, time limits, early stop with the child processes counted), parity with the core over 15 kinds of source, properties against the core as the oracle, the proof of gain, and the code blocks of the documentation.
  • Parity and properties: selectParallel()/whereParallel()/selectManyParallel()/eachParallel() answer as the core select()/where()/selectMany()/each() (keys, values, order, declared shape), with 1 worker and with 4 identically; 200 seeded inputs per property with 1, 2 and 4 workers.
  • Mutation testing: Infection over the whole src/ but the worker script, MSI 98.05% on 12 CPUs and 97.81% pinned to 2 CPUs, the size of a CI runner (at most 9 escaped mutants, all equivalent); the Quality workflow requires 97%, one integer below the worst run on 2 CPUs.
  • The report, the timing table and the mutation run: Tests.

🗺️ Roadmap & Ecosystem

The release shipped and what comes next: Roadmap. The milestone view: 👉 ROADMAP.md. The core and its own roadmap: Antevemus.AlinqCollection; the asynchronous companion, for non-blocking I/O: Antevemus.AlinqRevolt.

📄 License & Authors

This software is open-source, licensed under the MIT License.