reptily/async-run

Library for asynchronous launch

Maintainers

Package info

github.com/reptily/async-run

pkg:composer/reptily/async-run

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

3.1 2026-02-27 06:55 UTC

This package is auto-updated.

Last update: 2026-02-27 06:56:46 UTC


README

composer require reptily/async-run

Example use as object

Example file: /example/async_run.php

This library provides several methods for working with asynchronicity.

When an object is initialized in the constructor, parameters are available.

new AsyncRun(
    int $coresCount = 1,             // Count of running threads
    string $pathTmpDir = '/tmp',     // path to temporary files directory
    ?string $lockFileName = null     // filename for locale
);

Example use as callbacks

Example file: /example/async.php

You can easily use the library within your code.

To do this, fill in the necessary functions in the run(...function) method

After this, all the functions specified in run() will be executed, if there is success, then() will be called, if there is an error, catch() will be called, the finally() method will be called in any of the above cases.

Async::run(
    function () {
        sleep(1);
        echo "AAA" . PHP_EOL;
    },
    function () {
        echo "BBB" . PHP_EOL;
    }
)->then(function () {
    echo "CCC" . PHP_EOL;
})->finally(function () {
    echo "DDD" . PHP_EOL;
})->catch(function ($errorText) {
    echo "Error " . $errorText . PHP_EOL;
});

Example with Shared Memory and Mutex

Example file: /example/async_memory.php

This example demonstrates how to use shared memory and mutex for thread-safe operations in asynchronous execution.

Performance Note: In SharedMemoryContainer, both numeric and string keys can be used with get() and set() methods, but using numeric keys provides better performance.

$fns = [];
for ($i = 1; $i <= 500; $i++) {
    $fns[] = function (SharedMemoryContainer $memory, Mutex $mutex) {
        $mutex->lock();
        $data = $memory->get('transaction') ?? ['moneySeller' => 0 , 'moneyBuyer' => 1000];
        $data['moneySeller']++;
        $data['moneyBuyer']--;
        $memory->set('transaction', $data);
        $mutex->unlock();
    };
}

Async::run(...$fns)->finally(function (array $memory) {
    var_dump($memory);
    /*
    array(1) {
        'transaction' =>
            array(2) {
                'moneySeller' => int(500)
                'moneyBuyer' => int(500)
            }
    }
    */
});

Example: Race Conditions and Solutions

Example file: /example/async_race_conditions.php

This example demonstrates race conditions in concurrent programming and shows how to solve them using mutex locks.

Problem 1: Variable scope issues

$fns = [];
$money = 0;
for ($i = 1; $i <= 1000; $i++) {
    $fns[] = function () use (&$money){
        $money++;
    };
}
Async::run(...$fns);
echo $money . PHP_EOL; // 0 -> error (variable scope issue)

Problem 2: Race conditions with shared memory

$fns = [];
for ($i = 1; $i <= 1000; $i++) {
    $fns[] = function (SharedMemoryContainer $memory) {
        $money = $memory->get(1) ?? 0;
        $money++;
        $memory->set(1, $money);
    };
}
Async::run(...$fns)->finally(function (array $memory) {
    echo $memory[1] . PHP_EOL; // 998 != 1000 (race condition)
});

Solution: Using Mutex for thread-safe operations

$fns = [];
for ($i = 1; $i <= 1000; $i++) {
    $fns[] = function (SharedMemoryContainer $memory, Mutex $mutex) {
        $mutex->lock();
        $money = $memory->get(1) ?? 0;
        $money++;
        $memory->set(1, $money);
        $mutex->unlock();
    };
}
Async::run(...$fns)->finally(function (array $memory) {
    echo $memory[1] . PHP_EOL; // 1000 (correct result)
});

Methods

init - Object initialization method, used for prelaunch configuration.

protected function init(): void
{
    $this->arrayTest = [
        [self::FIELD_NAME => 'Bob'],
        [self::FIELD_NAME => 'Mark'],
        [self::FIELD_NAME => 'Ana'],
    ];
}

getError - Error return method.

protected function getError(string $message): void
{
    print_r($message);
}

done - The method is run after the entire execution, as a rule, it serves to generate a report.

protected function done(): void
{
    echo "Done in " . $this->getProgressTime() . " sec.\n";
}

unlock - Method for pre-unblocking.

(new Example(2))->unlock();

run - Method to run handlers.

(new Example(2))->run();

workerAfterSpawn - Method starts before each worker and distributes tasks to them.

protected function workerAfterSpawn(): void
{
    next($this->arrayTest);
}

getWorkerResults - The method returns the result of the worker's work.

protected function getWorkerResults(): void
{
    $item = current($this->arrayTest);
    echo $item[self::FIELD_NAME] . "\n";
}

getWorkerDoneCondition - The method serves as a pointer to the completion of processing all jobs.

protected function getWorkerDoneCondition(): bool
{
    return current($this->arrayTest) === false;
}