У меня есть PHP-скрипт, который обрабатывает данные, загруженные из нескольких REST API, в стандартизированный формат и строит массив или таблицу этих данных. В настоящее время скрипт выполняет все синхронно и поэтому занимает слишком много времени.
Я пытался научиться выполнять функцию, которая извлекает и обрабатывает данные одновременно или асинхронно, чтобы общее время было временем самого медленного вызова. Из моих исследований кажется, что ReactPHP или Amp - правильные инструменты.
Однако мне не удалось создать тестовый код, который действительно выполняется правильно. Прилагается простой пример, где mysquare () представляет мою более сложную функцию. Из-за отсутствия в сети примеров того, чего я пытаюсь достичь, я был вынужден использовать метод грубой силы с тремя примерами, перечисленными в моем коде.
В1: Подходящий ли я инструмент для работы?
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);
}






Асинхронность не означает, что несколько потоков выполняются параллельно. Две функции могут действительно работать только в «одно и то же время», если они (например) выполняют операции ввода-вывода, такие как HTTP-запрос.
usleep () блокирует, поэтому вы ничего не получите. И ReactPHP, и Amp сами будут иметь некую функцию «сна», которая встроена прямо в цикл событий.
По той же причине вы можете нет просто использовать curl, потому что он также будет блокироваться из коробки. Вам необходимо использовать библиотеки HTTP, которые предоставляют и рекомендуют React и Amp.
Поскольку ваша конечная цель - просто выполнять HTTP-запросы, вы также не используете мог ни одну из этих структур, а просто используете функции curl_multi. Однако их немного сложно использовать.
Спасибо @Evert. Я не могу использовать curl_multi или одну из включенных HTTP-библиотек, потому что мой код зависит от другой библиотеки, которая сама вызывает CURL_GET и т. д. Поэтому мне нужно иметь возможность выполнять несколько вызовов myfunction () «одновременно»
из ссылка на сайт. Вот почему многопоточность - не лучшее решение в такой среде. Если вы ищете многопоточность как решение задач блокировки ввода-вывода (таких как выполнение HTTP-запросов), позвольте мне указать вам в направлении асинхронного программирования, которое может быть достигнуто с помощью таких фреймворков, как Amp.
@Viktorius, если вы застряли в использовании другой библиотеки, которая выполняет HTTP-запросы, я бы сказал, что с вероятностью 99% эта библиотека выполняет асинхронные вызовы, и асинхронная структура не может вам здесь помочь. Асинхронные фреймворки зависят от библиотек, которые передают управление обратно своему циклу обработки событий, когда они ждут ввода-вывода (сетевой / дисковый и т. д.), Чтобы выполнить свою работу.
Итак, если это ваши ограничения, я бы посоветовал посмотреть в другом направлении: можете ли вы просто запустить несколько процессов PHP, каждый из которых выполняет свою часть работы?
библиотека использует стандартные вызовы curl в соответствии с ссылка на сайт, и я видел, как разработчики обсуждали добавление async в библиотеку php, но не определились, какую платформу использовать. Так что это еще не реализовано.
Сегодня вы можете выполнять асинхронность с PHP, иначе такие фреймворки, как ReactPHP, были бы невозможны. Дело в том, что вам нужна поддержка библиотеки. У вашей библиотеки нет поддержки, поэтому вы не можете этого сделать.
Я отвечаю на свой вопрос, пытаясь помочь другим пользователям, однако это решение было разработано самостоятельно без помощи опытного программиста, поэтому я не знаю, является ли это лучшим способом сделать это.
Я перешел с 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)», устранила эту проблему.
Вы правы, amphp/parallel-functions использует под капотом потоки / дочерние процессы. Поскольку PHP не используется совместно, все, что передается между потоками / дочерними процессами, необходимо сериализовать и передать между рабочими. Он использует больше памяти, чем реализация неблокирующего ввода-вывода с одним циклом событий, но это другой подход, потому что иногда невозможно заменить реализацию блокировки. С amphp/parallel его можно переместить в рабочий пул, чтобы он не блокировал оставшееся приложение.
Кроме того, сценарий всегда запускается из интерфейса командной строки.