ajf/hanno

为 PHP 5.5 提供的基于生成器的异步 I/O

dev-master 2014-08-04 01:08 UTC

This package is not auto-updated.

Last update: 2024-09-10 02:34:13 UTC


README

Hanno 是一个用于在 PHP 中编写实时应用的异步事件循环系统。与一些类似的系统不同,它基于生成器,避免了回调的需要,大大简化了代码的读取和写入。

因为它使用生成器,所以它至少需要 PHP 5.5。

这个名字来自日语动词“反应”,反応する (Han'nō suru),指的是对反应器的使用,并致敬 ReactPHP。由于这个名字的日语发音是 Han'nō,所以实际上应该把“Hanno”读作两个分开的 'n' 声音,就像“Han'no”,但在实践中,每个人(包括我自己)都会说“Hanno” (/ˈhæ.noʊ/))。

我该如何使用它?

Hanno 是一个现代的自动加载库,支持 Composer,并通过 Packagist 提供。因此,只需要求 "ajf\Hanno" 包,就可以开始了。

Hanno 的基本结构元素是 任务。Hanno 中的任务简单地说就是普通的 Generator,它们会在完成之前迭代。背后的思想是,当你需要等待其他事情时,使用 yield 将控制权交给其他任务,这意味着你可以高效地同时做很多事情(例如处理多个请求),而不会相互干扰,也不需要多个线程。举一个相当无聊的例子,以下生成器产生一个相当无用的任务

function counter() {
    for ($i = 1; $i <= 3; $i++) {
        yield;
        echo "$i\n";
    }
}

为了同时运行多个任务,Hanno 提供了一个 Reactor 类来处理多个任务。例如,这里我们创建一个反应器并向它添加两个计数器

use ajf\Hanno as Hanno;
$reactor = new Hanno\Reactor;
$reactor->addTask(counter());
$reactor->addTask(counter());
$reactor->run();

对于反应器运行的每个步骤,它将执行每个任务,运行一次迭代(即调用其 ->next() 方法),如果它没有完成(即,->valid() 返回 true),则将其调度为下次运行。请注意,您也可以将反应器作为一个任务来运行,因此实际上可以在反应器中运行反应器!例如,我们可以这样做

$reactor1 = new Hanno\Reactor;
$reactor1->addTask(counter());
$reactor1->addTask(counter());

$reactor2 = new Hanno\Reactor;
$reactor2->addTask(counter());

$ueber_reactor = new Hanno\Reactor;
$ueber_reactor->addTask($reactor1->runAsTask());
$ueber_reactor->addTask($reactor2->runAsTask());

您可以将反应器嵌套在自身内部,但会发生 TM 糟糕的事情,所以不要尝试。 ;)

所以,现在我们已经熟悉了任务和反应器的基本知识。但如果我们想做一些真正有用的事情怎么办?反应器不会忽略 yield 产生的值。通过使用特殊的键 'until',您可以要求反应器挂起您的任务,直到某件事完成,并返回该任务的结果。那件事必须是一个 Awaitable 类。例如

function myTask($myAwaitable) {
    yield;
    
    $result = (yield 'until' => $myAwaitable);
    foobar($result);
}

但您从哪里获取可等待的对象呢?嗯,可等待的对象通常是由执行某些操作的函数返回的。它是一个非常简单的对象,包含一个反应器将运行的任务,反应器可以“监听”以知道工作何时完成以及其结果如何,以便您的任务可以再次开始运行。您可以从一个地方获取可等待的对象,那就是 Hanno 内置的 Stream 类,它包装了 PHP 流。假设我们想找出我们的 IP 地址。我们可以像这样使用 http://ip.jsontest.com/ API

function getIPTask() {
    yield;
    
    $stream = new Hanno\Stream("http://ip.jsontest.com/", "r");
    $data = (yield 'until' => $stream->read());
    $data = json_decode($data);
    var_dump($data->ip);
}
$reactor = new Hanno\Reactor;
$reactor->addTask(getIPTask());
$reactor->run();

构造函数接受现有的资源,或一个 URL 和一个模式(就像您提供给 fopen 的一样)。使用无参数的 ->read 方法将读取整个流并给我们一个最终结果为字符串的可等待对象。然后我们只需调用 json_decode

这就是 Hanno 的基础知识。祝您玩得开心!