lumetas/luper

1.2.0 2025-08-24 17:31 UTC

This package is not auto-updated.

Last update: 2025-09-07 17:48:00 UTC


README

Введение

О библиотеке

Luper - это легковесная библиотека для асинхронного программирования в PHP, предоставляющая механизмы для работы с параллельными задачами, таймерами и файберами.

Ключевые возможности

Асинхронное выполнение PHP-функций через отдельные процессы

Управление задачами с помощью Fibers (доступно с PHP 8.1)

Таймеры и периодические задачи

Неблокирующее ожидание результатов

Простой и интуитивно понятный API

Установка

Требования

PHP >= 8.1

Composer

composer require lumetas/luper

Основные компоненты

Async - Асинхронное выполнение

Класс для запуска PHP-функций в отдельных процессах.

Создание асинхронной задачи

<?php
use Luper\Async;

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

Запуск и ожидание результата

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

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

// Получение ошибки (если есть)
$error = $promise->getError();

Loop - Цикл событий

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

Создание экземпляра

<?php
use Luper\Loop;

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

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

Добавление задач

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

Таймеры

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

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

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

Управление выполнением

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

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

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

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

Пример использования

Базовый пример

<?php
require_once "vendor/autoload.php";
use Luper\Async;
use Luper\Loop;

$startTime = time();

function createRequests($count) {
	$loop = new Loop();
	$results = [];

	for($i = 0; $i < $count; $i++) {
		$loop->addTask(function () use (&$loop, &$results) {
			$asyncFunc = Async::create(__DIR__.'/requestFunc.php');
			$promise = $asyncFunc("https://google.com");

			while ($promise->getResult() === null) {
				$loop->suspend();
		 	}

			$results[] = strlen($promise->getResult()['result']);
		});
	}

	$loop->run();
	return $results;
}

var_dump(createRequests(10));
echo "\nИтоговое время: " . (time() - $startTime);

Пример файла requestFunc.php

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

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

Параллельные HTTP-запросы

<?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;
}

Периодические задачи

<?php
use Luper\Loop;

$loop = new Loop();

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

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

$loop->run();

Pull и PullMax

Это два класса представляющие собой обёртку над функционалом. Чтобы было проще обрабатывать данные Пример:

<?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, 'дополнительный_аргумент');
}

// Запускаем обработку
$results = $pull->run();

И аналогичный пример для PullMax:

<?php
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, 'дополнительный_аргумент');
}

// Запускаем обработку 
$results = $pull->run();

Класс Pull Позволяет легко обрабатывать данные, указав максимальное количество одновременно запущенных процессов. PullMax Будет пытаться запустить столько паралельных процессов сколько сможет

await

Асинхронная функция при выполнении возвращает промис, у которого есть метод await, он возвращает результат работы функции, если функция ещё не выполнена метод останавливает поток выполнения дожидаясь завершения, в случае если метод был вызван внутри файбера, то файбер будет приостанавливаться до завершения выполнения функции. Поэтому метод крайне полезно использовать внутри EventLoop, пример:

<?php
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();
	});
}
$loop->run();
var_dump($results);

Best Practices

Структура асинхронных функций

  • Каждая асинхронная функция должна быть в отдельном файле
  • Файл должен возвращать callable
  • Используйте обработку ошибок внутри функций

Управление памятью

  • Используйте ссылки для больших данных чтобы избежать копирования

Производительность

  • Не создавайте чрезмерное количество параллельных процессов

Ограничения

  • Ограничения процессов PHP (память, время выполнения)
  • Требует аккуратного управления ресурсами

Заключение

Luper предоставляет простой и эффективный способ асинхронного программирования в PHP, особенно полезный для I/O-операций и параллельной обработки задач.