使用生成器时,异步 php http 请求变得同步

问题描述 投票:0回答:1

我正在用 PHP 进行异步 http 请求的 POC 实现。当我们按照以下方式检索响应数据时,symfony http 客户端运行良好:

$response1 = $httpClient->request('GET', 'https://127.0.0.1:8000/service/a');
$response2 = $httpClient->request('GET', 'https://127.0.0.1:8000/service/b');

$array1 = $response1->toArray();
$array2 = $response2->toArray();

考虑到服务 A 和 B 都需要 5 秒来执行,我们的客户端代码总共只需等待 5 秒。

现在的问题是,通常我们会为不同的客户端编写不同的存储库(RepositoryA、RepositoryB)。因此,在客户端代码中,我们不会对简单的 HttpResponseInterface 对象进行操作,而是对某些 DTO 进行操作。

我想利用异步 http 请求,同时保留存储库分离。

简化的方法如下所示:

private function getResponse1(): Generator
{
    $response1 = $this->httpClient->request('GET', 'https://127.0.0.1:8000/service/a');

    return yield $response1->toArray();
}

private function getResponse2(): Generator
{
    $response2 = $this->httpClient->request('GET', 'https://127.0.0.1:8000/service/b');

    return yield $response2->toArray();
}

$response1 = $this->getResponse1();
$response2 = $this->getResponse2();

$array1 = $response1->current();
$array2 = $response2->current();

如果您熟悉 JS,那么对

current()
对象的
Generator
调用有点类似于
await 
构造。

最后的问题是,为什么这种方法行不通呢? 由于测量显示,使用发电机时总等待时间为 10 秒,而没有发电机时则只有 5 秒。

这是控制台命令,可用于重现该问题: https://github.com/rela589n/generator-as-promise-poc/blob/master/src/Command/TestSyncSfClientGeneratorsCommand.php

还有一个不使用生成器的代码的工作示例: https://github.com/rela589n/generator-as-promise-poc/blob/master/src/Command/TestAsyncSfHttpClientCommand.php

php symfony asynchronous generator reactphp
1个回答
0
投票

问题很可能是你的生成器的第一个产量就是总结果:

    return yield $response1->toArray();

(除了回报率现在有点假,因为我将其粘贴到...)

现在生成器也在进行资源获取:

    $response1 = $this->httpClient->request('GET', 'https://127.0.0.1:8000/service/a');

在返回的yield前面,这意味着生成器将等待该请求完成。

第二个发电机也一样。

因此,当您将两个请求分发到两个不同的生成器中时,您将失去并行调用它们的能力(如在彼此之后),就像您已经通过生成器实现所做的那样 - 生成器等待第一个收益 因此,伪造第一个产量并进行返回构造。

private function getResponse2(): Generator { $response2 = $this->httpClient->request('GET', 'https://127.0.0.1:8000/service/b'); yield $response2; # first current() (implicit rewind()) stops here after invocation. return yield $response2->toArray(); # second current() fetches the result }

这可能会起作用,但是我仍然不清楚 toArray() 实际做了什么,因为我不知道该库。

但是,对于 PHP Generator 实现,它总是完全初始化,这就是它无法倒带的原因。

因此第一个yield一定是http-client-request协议的非阻塞结果。

© www.soinside.com 2019 - 2024. All rights reserved.