Как правильно превратить замыкание в ампхп? - PullRequest
0 голосов
/ 05 октября 2018

Я учу Amphp.Я хочу преобразовать синхронный вызов в асинхронный вызов, используя цикл обработки событий в amphp.Мой образец кода использует file_get_contents в качестве примера вызова блокировки.

Используя синхронизирующий вызов, это выглядит следующим образом:

$uris = [
    "https://google.com/",
    "https://github.com/",
    "https://stackoverflow.com/",
];

$results = [];
foreach ($uris as $uri) {
    var_dump("fetching $uri..");
    $results[$uri] = file_get_contents($uri);
    var_dump("done fetching $uri.");
}

foreach ($results as $uri => $result) {
    var_dump("uri : $uri");
    var_dump("result : " . strlen($result));
}

И вывод:

string(30) "fetching https://google.com/.."
string(34) "done fetching https://google.com/."
string(30) "fetching https://github.com/.."
string(34) "done fetching https://github.com/."
string(37) "fetching https://stackoverflow.com/.."
string(41) "done fetching https://stackoverflow.com/."
string(25) "uri : https://google.com/"
string(14) "result : 48092"
string(25) "uri : https://github.com/"
string(14) "result : 65749"
string(32) "uri : https://stackoverflow.com/"
string(15) "result : 260394"

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

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

string(30) "fetching https://google.com/.."
string(30) "fetching https://github.com/.."
string(37) "fetching https://stackoverflow.com/.."
string(34) "done fetching https://google.com/."
string(34) "done fetching https://github.com/."
string(41) "done fetching https://stackoverflow.com/."
string(25) "uri : https://google.com/"
string(14) "result : 48124"
string(25) "uri : https://github.com/"
string(14) "result : 65749"
string(32) "uri : https://stackoverflow.com/"
string(15) "result : 260107"

I 'я пробовал с этим кодом:

<?php
require __DIR__ . '/vendor/autoload.php';

use Amp\Loop;
use function Amp\call;

Loop::run(function () {
    $uris = [
        "https://google.com/",
        "https://github.com/",
        "https://stackoverflow.com/",
    ];

    foreach ($uris as $uri) {
        $promises[$uri] = call(function () use ($uri) {
            var_dump("fetching $uri..");
            $result = file_get_contents($uri);
            var_dump("done fetching $uri.");
            yield $result;
        });
    }

    $responses = yield $promises;

    foreach ($responses as $uri => $result) {
        var_dump("uri : $uri");
        var_dump("result : " . strlen($result));
    }
});

Вместо этого, давая мне ожидаемый результат, он дает мне эту ошибку:

string(30) "fetching https://google.com/.."
string(34) "done fetching https://google.com/."
string(30) "fetching https://github.com/.."
string(34) "done fetching https://github.com/."
string(37) "fetching https://stackoverflow.com/.."
string(41) "done fetching https://stackoverflow.com/."
PHP Fatal error:  Uncaught Amp\InvalidYieldError: Unexpected yield; Expected an instance of Amp\Promise or React\Promise\PromiseInterface or an array of such instances; string yielded at key 0 on line 20 

Результат также, кажется, выполняется синхронно, а не асинхронно.

Как мне правильно это сделать?

1 Ответ

0 голосов
/ 04 января 2019

Вам нужно использовать неблокирующие реализации функций, которые вы используете.file_get_contents блокируется.Вы можете найти неблокирующую реализацию, например, в amphp/file.Если вы замените file_get_contents на Amp\File\get, он должен работать как положено.

...