У меня есть 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 функции могут действительно выполняться только в одно и то же время, если они (например) выполняют IO, например, HTTP-запрос.
блоки usleep (), так что вы ничего не получите. И ReactPHP, и Amp сами будут иметь какую-то функцию «сна», встроенную прямо в цикл обработки событий.
По той же причине вы будете не быть в состоянии просто использовать curl, потому что он также будет блокировать из коробки. Вам нужно использовать HTTP-библиотеки, которые React и Amp предоставляют и / рекомендуют.
Поскольку ваша конечная цель — просто выполнение HTTP-запросов, вы мог также не используйте ни одну из этих платформ, а просто используйте функции curl_multi. Они немного сложны в использовании, хотя.
Я отвечаю на свой собственный вопрос, пытаясь помочь другим пользователям, однако это решение было разработано в одиночку без помощи опытного программиста, и поэтому я не знаю, является ли это в конечном итоге лучшим способом сделать это.
Я перешел с 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 ().
В моем реальном случае использования я смог получить данные через HTTP из 90 отдельных источников примерно за 5 секунд.
amphp/parallel-functions
Библиотека, кажется, использует темы под капотом. Исходя из моего предварительного опыта, кажется, что для этого требуется гораздо больше памяти, чем для однопоточного скрипта PHP, но я еще не до конца понял. Это было подчеркнуто, когда я передавал большой массив в $ mysquare через выражение «use ($ myarray)», и размер массива составлял 65 МБ. Это привело к тому, что код зашел в тупик и экспоненциально увеличил время выполнения, так что потребовались порядки величины дольше чем синхронное исполнение. Кроме того, использование памяти достигло 5G! в какой-то момент я понял, что amphp дублирует $ myarray для каждого экземпляра. Переработка моего кода, чтобы избежать выражения «use ($ myarray)», устранила эту проблему.