1

我有一个 PHP 脚本,它将从多个 REST API 下载的数据处理为标准化格式,并构建此数据的数组或表。该脚本当前同步执行所有内容,因此需要很长时间。

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

但是,我未能成功创建实际正确执行的测试代码。附上一个简单的例子,mysquare() 代表我更复杂的函数。由于网络上缺乏我想要达到的目标的示例,我被迫使用蛮力方法,在我的代码中列出了 3 个示例。

Q1:我是否使用了正确的工具来完成这项工作?

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

注意:我是一个真正的初学者,所以使用最少高级编程术语的最简单的代码示例将不胜感激。

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

2 回答 2

1

异步并不意味着多个线程并行执行。如果两个函数(例如)执行诸如 HTTP 请求之类的 IO,则它们只能在“同时”真正运行。

usleep() 阻塞,所以你一无所获。ReactPHP 和 Amp 本身都将具有某种“睡眠”功能,这些功能直接内置到事件循环中。

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

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

于 2018-07-13T01:29:51.383 回答
0

我正在回答我自己的问题以帮助其他用户,但是这个解决方案是在没有经验丰富的程序员帮助的情况下单独开发的,所以我不知道它最终是否是最好的方法。

TL;博士

我从 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)”表达式解决了这个问题。

于 2018-07-16T00:37:09.947 回答