Не удается получить обещания ReactPHP выполнить асинхронно

У меня есть 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);
}

Кроме того, сценарий всегда запускается из интерфейса командной строки.

Viktorius 13.07.2018 05:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
1
962
2

Ответы 2

Асинхронность не означает, что несколько потоков выполняются параллельно. Две функции могут действительно работать только в «одно и то же время», если они (например) выполняют операции ввода-вывода, такие как HTTP-запрос.

usleep () блокирует, поэтому вы ничего не получите. И ReactPHP, и Amp сами будут иметь некую функцию «сна», которая встроена прямо в цикл событий.

По той же причине вы можете нет просто использовать curl, потому что он также будет блокироваться из коробки. Вам необходимо использовать библиотеки HTTP, которые предоставляют и рекомендуют React и Amp.

Поскольку ваша конечная цель - просто выполнять HTTP-запросы, вы также не используете мог ни одну из этих структур, а просто используете функции curl_multi. Однако их немного сложно использовать.

Спасибо @Evert. Я не могу использовать curl_multi или одну из включенных HTTP-библиотек, потому что мой код зависит от другой библиотеки, которая сама вызывает CURL_GET и т. д. Поэтому мне нужно иметь возможность выполнять несколько вызовов myfunction () «одновременно»

Viktorius 13.07.2018 05:58

из ссылка на сайт. Вот почему многопоточность - не лучшее решение в такой среде. Если вы ищете многопоточность как решение задач блокировки ввода-вывода (таких как выполнение HTTP-запросов), позвольте мне указать вам в направлении асинхронного программирования, которое может быть достигнуто с помощью таких фреймворков, как Amp.

Viktorius 13.07.2018 06:03

@Viktorius, если вы застряли в использовании другой библиотеки, которая выполняет HTTP-запросы, я бы сказал, что с вероятностью 99% эта библиотека выполняет асинхронные вызовы, и асинхронная структура не может вам здесь помочь. Асинхронные фреймворки зависят от библиотек, которые передают управление обратно своему циклу обработки событий, когда они ждут ввода-вывода (сетевой / дисковый и т. д.), Чтобы выполнить свою работу.

Evert 13.07.2018 17:53

Итак, если это ваши ограничения, я бы посоветовал посмотреть в другом направлении: можете ли вы просто запустить несколько процессов PHP, каждый из которых выполняет свою часть работы?

Evert 13.07.2018 17:54

библиотека использует стандартные вызовы curl в соответствии с ссылка на сайт, и я видел, как разработчики обсуждали добавление async в библиотеку php, но не определились, какую платформу использовать. Так что это еще не реализовано.

Viktorius 16.07.2018 02:17

Сегодня вы можете выполнять асинхронность с PHP, иначе такие фреймворки, как ReactPHP, были бы невозможны. Дело в том, что вам нужна поддержка библиотеки. У вашей библиотеки нет поддержки, поэтому вы не можете этого сделать.

Evert 16.07.2018 03:25

Я отвечаю на свой вопрос, пытаясь помочь другим пользователям, однако это решение было разработано самостоятельно без помощи опытного программиста, поэтому я не знаю, является ли это лучшим способом сделать это.

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 ().

В моем фактическом случае использования я смог получить данные через HTTP из 90 отдельных источников примерно за 5 секунд.

Заметки:

Библиотека amphp/parallel-functions, похоже, использует внутренние потоки. Судя по моему предварительному опыту, это требует гораздо больше памяти, чем просто однопоточный PHP-скрипт, но я еще не убедился в полном воздействии. Это было подчеркнуто, когда я передавал большой массив $ mysquare через выражение "use ($ myarray)", и размер массива составлял 65 МБ. Это остановило код и увеличило время выполнения настолько экспоненциально, что потребовалось дольше на порядки, чем синхронное выполнение. Кроме того, использование памяти превысило 5G! в какой-то момент заставил меня поверить, что amphp дублирует $ myarray для каждого экземпляра. Переработка моего кода, чтобы избежать выражения «use ($ myarray)», устранила эту проблему.

Вы правы, amphp/parallel-functions использует под капотом потоки / дочерние процессы. Поскольку PHP не используется совместно, все, что передается между потоками / дочерними процессами, необходимо сериализовать и передать между рабочими. Он использует больше памяти, чем реализация неблокирующего ввода-вывода с одним циклом событий, но это другой подход, потому что иногда невозможно заменить реализацию блокировки. С amphp/parallel его можно переместить в рабочий пул, чтобы он не блокировал оставшееся приложение.

kelunik 03.08.2018 20:48

Другие вопросы по теме