sue/event-loop

提供基于reactphp的event-loop

1.2.0 2023-09-25 10:33 UTC

This package is auto-updated.

Last update: 2024-09-25 15:25:51 UTC


README

提供基于ReactPHP的全局唯一的EventLoop

什么是ReactPHP?

ReactPHP是一款基于PHP的事件驱动组件。核心是提供EventLoop,然后基于EventLoop提供各种组件,比如I/O处理,定时器等。

目录

loop

获取全局唯一的eventLoop对象

use Sue\EventLoop\loop;

$loop = loop();

//loop启动后程序就会阻塞在这
//如果loop上没有任何待处理的callback, loop则自动退出
$loop->run();

//loop停止运行
$loop->stop(); 

isLoopRunning

判断全局的eventloop是否正在运行中

setInterval(1, function () {
    if (isLoopRunning()) {
        echo "Loop is running";
    }
});
loop()->run();

await

await($promise, $timeout)启动一个临时eventloop来处理promise,当promise被settle后终止当前eventloop。该方法适用于传统的阻塞php模型(比如php-fpm)中使用异步的特性。方法返回promise resolved的值或者抛出异常 *** 该方法无法在一个已启动eventloop中使用 ***

try {
    $promise = someIoHeavyOperation();
    $result = await($promise); //程序会阻塞在这里一直等待$promise被resolved或者rejected
    handle($result);
} catch (Throwable $e) {
    //error handle
} 
//await方法第个参数接受一个float作为promise的timeout,以免promise长时间阻塞程序流程
$result = await($promise, 10);

setTimeout

setTimeout方法可以在eventloop上添加一个一次性的timer

use Sue\EventLoop\setTimeout;
use Sue\EventLoop\loop;
use Sue\EventLoop\cancelTimer;

 //延迟5秒执行
setTimeout(5, function () {
    echo "hello world from 5 seconds ago";
});
loop()->run();

//提前终止执行
$timer = setTimeout(5, function () {
    echo "hello world from 5 seconds ago";
});
cancelTimer($timer);
loop()->run();

setInterval

setInterval方法可以在eventloop上添加一个可以重复执行的timer

use React\EventLoop\TimerInterface;

use function Sue\EventLoop\setInterval;
use function Sue\EventLoop\cancelTimer;

//每60秒执行一次
setInterval(60, function () {
    echo "one minute has been passed\n";
});

// 中止运行
$timer = setInterval(1, function (string $name, int $age, TimerInterface $timer) {
    if ($some_condition) {
        cancelTimer($timer);
    }
}, 'foo', 18);
loop()->run();

cancelTimer

cancelTimer可以取消一个已经注册的timer对象

use React\EventLoop\TimerInterface;

use function Sue\EventLoop\setInterval;
use function Sue\EventLoop\cancelTimer;

$timer = setInterval(1, function (TimerInterface $timer) {
        echo "working...\n";
});
if ($some_condition) {
    cancelTimer($timer);
}

nextTick

nextTick可以在eventloop上注册一个在下一轮tick时执行的回调,对比setTimeout(0, $callback)nextTick($callback)有更高优先级

use RuntimeException;
use Sue\EventLoop\Exceptions\PromiseCancelledException;

use function Sue\EventLoop\nextTick;

$promise = nextTick(function () {
    return "hello world";
});
$promise->then(function (string $content) {
    //handler
});

//异常处理
$promise = nextTick(function () {
    throw new RuntimeException('boom');
});
$promise->then(null, function (RuntimeException $e) {
    echo "error: " . $e;
});

//中止执行
$promise = nextTick(function () {
    return "hello world";
});
if ($some_condition) {
    $promise->cancel();
}
$promise->otherwise(function (PromiseCancelledException $exception) {
    //exception
});

throttle

throttle(节流)可以在eventloop上创建一个一次性的timer,但是会在N秒内同样的操作只会执行一次

use Sue\EventLoop\loop;
use Sue\EventLoop\throttle;
use Sue\EventLoop\setInterval;

$callback = function () {
    echo "hello world\n";
};
setInterval(1, function () use ($callback) {
    static $count = 10;
    while ($count--) {
        echo "tick\n";
        throttle(3, $callback);
    }
});
loop()->run();

/** expect output
tick
tick
tick
hello world
tick
tick
tick
hello world
tick
tick
tick
hello world
tick
**/

//如果想提前手动中止
$promise = throttle(3, $callback);
if ($some_condition) {
    $promise->cancel();
}
$promise->otherwise(function (PromiseCancelledException $exception) {
    //exception
});

throttleById

throttleById方法同throttle,除了需要自行设置唯一id值,throttle是由callable的性质来计算唯一id

debounce

debounce(防抖)可以在eventloop上注册一个一次性timer,但是在N秒内每次同样的操作都会延迟N秒后再执行

use Sue\EventLoop\loop;
use Sue\EventLoop\debounce;
use Sue\EventLoop\setInterval;

$callback = function () {
    echo "hello world\n";
};
debounce(1, function () use ($callback) {
    static $count = 10;
    while ($count--) {
        echo "tick\n";
        throttle(3, $callback);
    }
});
loop()->run();
/** expect output
tick
tick
tick
tick
tick
tick
tick
tick
tick
tick
hello world
**/

//如果想提前中止
$promise = debounce(1, $callback);
if ($some_condition) {
    $promise->cancel();
}
$promise->otherwise(function (PromiseCancelledException $exception) {
    //exception
});

debounceById

debounceById方法同debounce,除了需要自行设置唯一id值

install

$ composer require sue/event-loop

tests

克隆项目后执行

$ composer install
$ ./vendor/bin/phpunit

许可证

MIT许可证 (MIT)

版权所有 (c) 2023 张东海

在此特此授予任何获得本软件及其相关文档副本(以下简称“软件”)的人士,免费、不可撤销的使用、复制、修改、合并、发布、分发、再许可和/或出售副本的权利,并允许软件的接受者进行上述操作,前提是

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

本软件按“现状”提供,不提供任何明示或暗示的保证,包括但不限于适销性、针对特定目的的适用性和非侵权性。在任何情况下,作者或版权所有者不对任何索赔、损害或其他责任(无论因合同、侵权或其他方式引起)承担责任,即使已收到有关软件或其使用的通知。