无法获得ReactPHP承诺异步执行

时间:2018-07-13 01:11:04

标签: php asynchronous reactphp amphp

我有一个PHP脚本,该脚本将从多个REST API下载的数据处理为标准化格式,并构建此数据的数组或表。该脚本当前会同步执行所有操作,因此耗时太长。

我一直在尝试学习如何同时执行或异步执行获取和处理数据的功能,以便总时间是最慢的调用时间。从我的研究看来,ReactPHP或Amp是正确的工具。

但是,我未能创建能够正确执行的测试代码。附带一个简单的示例,其中mysquare()代表了我更复杂的功能。由于网上缺少我想要达到的目标的示例,因此我不得不使用蛮力方法,并在代码中列出了3个示例。

Q1:我在使用正确的工具来完成工作吗?

Q2:您可以修复我的示例代码以异步执行吗?

NB:我是一个真正的初学者,因此,请尽可能使用最少的高级编程术语的最简单的代码示例。

<?php
require_once("../vendor/autoload.php");

for ($i = 0; $i <= 4; $i++) {

    // Experiment 1
    $deferred[$i] = new React\Promise\Deferred(function () use ($i) {
        echo $x."\n";
        usleep(rand(0, 3000000));  // Simulates long network call
        return array($x=> $x * $x);
    });

    // Experiment 2
    $promise[$i]=$deferred[$i]->promise(function () use ($i) {
        echo $x."\n";
        usleep(rand(0, 3000000));  // Simulates long network call
        return array($x=> $x * $x);
    });

    // Experiment 3
    $functioncall[$i] = function () use ($i) {
        echo $x."\n";
        usleep(rand(0, 3000000));  // Simulates long network call
        return array($x=> $x * $x);
    };
}

$promises = React\Promise\all($deferred); // Doesn't work
$promises = React\Promise\all($promise); // Doesn't work
$promises = React\Promise\all($functioncall); // Doesn't work

// print_r($promises);  // Doesn't return array of results but a complex object

//  This is what I would like to execute simulatenously with a variety of inputs
function mysquare($x)
{
    echo $x."\n";
    usleep(rand(0, 3000000));  // Simulates long network call
    return array($x=> $x * $x);
}

2 个答案:

答案 0 :(得分:1)

异步并不意味着多个线程并行执行。如果2个功能(例如)执行IO(例如HTTP请求),则它们只能在“相同时间”真正运行。

usleep()阻止,因此您一无所获。 ReactPHP和Amp本身都会在事件循环中内置某种“睡眠”功能。

出于相同的原因,您不能只能使用curl,因为它也会开箱即用。您需要使用React和Amp提供和/推荐的HTTP库。

由于最终目标只是在执行HTTP请求,因此您也可以不使用任何这些框架,而只使用curl_multi函数。但是,它们有点难用。

答案 1 :(得分:0)

我正在回答自己的问题,以帮助其他用户,但是,此解决方案是在没有经验丰富的程序员的帮助下独自开发的,因此我不知道这最终不是实现此目的的最佳方法。

TL; DR

我从ReactPHP切换了,因为我不理解它,而使用amphp/parallel-functions,它提供了简化的最终用户界面...使用此接口的示例代码。

<?php
require_once("../vendor/autoload.php");

use function Amp\ParallelFunctions\parallelMap;
use function Amp\Promise\wait;

$start = \microtime(true);

$mysquare = function ($x) {
    sleep($x);  // Simulates long network call
    //echo $x."\n";
    return $x * $x;
};

print_r(wait(parallelMap([5,4,3,2,1,6,7,8,9,10], $mysquare)));

print 'Took ' . (\microtime(true) - $start) . ' milliseconds.' . \PHP_EOL;

示例代码在10.2秒内执行,这比运行时间最长的$ mysquare()稍长。

在我的实际用例中,我能够在5秒钟内通过HTTP从90个单独的源中获取数据。

注意:

amphp/parallel-functions库似乎在后台使用线程。从我的初步经验来看,这似乎需要比单线程PHP脚本更多的内存,但是我尚未确定全部影响。当我通过“ use($ myarray)”表达式将一个大型数组传递给$ mysquare时,这一点特别突出,数组为65Mb。这使代码陷入停顿,并且执行时间成倍增加,以至于与同步执行相比,它们花了更长的时间。内存使用量也达到了5G以上的峰值!有一次让我相信amphp正在为每个实例复制$ myarray。重新编写代码以避免“ use($ myarray)”表达式解决了该问题。