Как правильно превратить замыкание в обещание в amphp?

Я учу 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"

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

Я полагаю, что правильный вывод, если я успешно реализую его в 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"

Я пробовал с этим кодом:

<?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

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

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

0

Решение

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]