PHP code example of lumetas / luper

1. Go to this page and download the library: Download lumetas/luper library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

lumetas / luper example snippets


use Luper\Async;

// Создание асинхронной функции из файла
$asyncFunction = Async::create(__DIR__.'/my_function.php');
#+END_SRC

*** Запуск и ожидание результата
#+BEGIN_SRC php

// Запуск с аргументами
$promise = $asyncFunction("arg1", "arg2");

// Проверка завершения
if ($promise->isCompleted()) {
	$result = $promise->getResult();

$promise = $asyncFunction(...);

// Неблокирующая отправка данных в дочерний процесс
$promise->sendData('hello');
$promise->sendData(['key' => 'value']);
#+END_SRC

Внутри дочерней функции данные принимаются через luper_get_data().

*** Дочерний процесс -> Родитель
#+begin_src php

return function() {
    // Отправка данных родителю
    luper_send_data('progress: 50%');
    luper_send_data(['status' => 'working']);

    return 'final result';
};
#+end_src

Родитель получает их через $promise->getData().

*** Методы
- $promise->sendData($data) - неблокирующая отправка данных в дочерний процесс. Выполнение не останавливается даже при переполнении канала (данные буферизуются).
- $promise->getData(bool $nonBlocking = false) - получить данные от дочернего процесса. По умолчанию ожидает появления данных (внутри файбера приостанавливает его). Если передать true - вернёт null сразу, когда готовых данных нет.
- luper_get_data(bool $nonBlocking = false) - получить данные, отправленные через $promise->sendData(). Семантика та же, что у getData.
- luper_send_data($data) - отправить данные родителю; они попадают в очередь $promise->getData().

*** Пример обмена
#+begin_src php

// worker.php - дочерняя функция
return function(int $count) {
    for ($i = 0; $i < $count; $i++) {
        luper_send_data("progress: $i/$count");
        usleep(100000);
    }
    $command = luper_get_data(); // ждём команду от родителя
    return $command;
};
#+end_src

#+begin_src php

$promise = Async::create(__DIR__ . '/worker.php')(3);

// Читаем промежуточные данные (блокирует, пока данных нет)
var_dump($promise->getData()); // "progress: 0/3"
var_dump($promise->getData()); // "progress: 1/3"

// Неблокирующая проверка: данных ещё нет -> null
var_dump($promise->getData(true));

$promise->sendData('СТАРТ');

var_dump($promise->await()); // "СТАРТ"
#+end_src

** Loop - Цикл событий
Центральный класс для управления асинхронными задачами.

*** Создание экземпляра
#+BEGIN_SRC php

use Luper\Loop;

// Создание нового цикла
$loop = new Loop();

// Или использование синглтона
$loop = Loop::make();
#+END_SRC

*** Добавление задач
#+BEGIN_SRC php

$loop->addTask(function () {
// Ваш код здесь
	echo "Выполнено в файбере!";
});
#+END_SRC

*** Таймеры
#+BEGIN_SRC php

// Одноразовый таймер
$timerId = $loop->addTimer(2.5, function () {
	echo "Выполнится через 2.5 секунды";
});

// Периодический таймер
$repeatingTimerId = $loop->addTimer(1.0, function () {
	echo "Выполняется каждую секунду";
}, true);

// Отмена таймера
$loop->clearTimer($timerId);
#+END_SRC

*** Управление выполнением
#+BEGIN_SRC php

// Запуск цикла
$loop->run();

// Остановка цикла
$loop->stop();

// Приостановка выполнения в файбере
Loop::suspend();

// Задержка выполнения
$loop->sleep(0.5); // sleep на 0.5 секунды
#+END_SRC

* Пример использования
** Базовый пример
#+BEGIN_SRC php


// Файл должен возвращать callable функцию
return function($url) {
// Имитация HTTP-запроса
sleep(1); // Длительная операция
return [
	'status' => 200,
	'content' => file_get_contents($url),
	'headers' => []
];
};
#+END_SRC

* Практические примеры

** Параллельные HTTP-запросы
#+BEGIN_SRC php

use Luper\Async;
use Luper\Loop;

function fetchMultipleUrls(array $urls) {
	$loop = new Loop();
	$responses = [];

	foreach ($urls as $index => $url) {
		$loop->addTask(function () use ($url, $index, &$responses, $loop) {
			$fetch = Async::create(__DIR__.'/fetch_url.php');
			$promise = $fetch($url);

			while (!$promise->isCompleted()) {
				Loop::suspend();
			}

			$responses[$index] = $promise->getResult();
		});
	}

	$loop->run();
	return $responses;

use Luper\Loop;

$loop = new Loop();

// Обновление кэша каждые 30 секунд
$loop->addTimer(30, function () {
	updateCache();
}, true);

// Одноразовая задача через 5 секунд
$loop->addTimer(5, function () {
	sendNotification();
});

$loop->run();
#+END_SRC

** closure
#+begin_src php

налом. Чтобы было проще обрабатывать данные Пример:
#+begin_src php

use Luper\Pull;

$items = [];
for($i = 0; count($items) < 50; $i ++) {$items[] = $i;}

$pullSize = 10;
// Создаем пул с максимум 3 параллельными процессами
$pull = new Pull($pullSize, __DIR__.'/proc.php');

// Добавляем задачи
foreach ($items as $item) {
    $pull->add($item, 'дополнительный_аргумент');

use Luper\PullMax;

$items = [];
for($i = 0; count($items) < 50; $i ++) {$items[] = $i;}

$pullSize = 10;

$pull = new PullMax(__DIR__.'/proc.php');

// Добавляем задачи
foreach ($items as $item) {
    $pull->add($item, 'дополнительный_аргумент');

use Luper\{Loop, Async};
$func = Async::create(__DIR__.'/proc.php');
$loop = new Loop;
$results = [];
foreach ($elems as $elem) {
	$loop->addTask(function () use ($func, $loop, &$results) {
		$results[] = $func(1, 2)->await();
	});