【问题标题】:How to limit number of connections at a time while requesting an enormous number of requests, enqueuing them as responses are received?如何在请求大量请求时限制一次连接数,并在收到响应时将它们排入队列?
【发布时间】:2021-01-22 00:14:17
【问题描述】:

假设我必须发出大量 HTTP 请求(并获得响应)。我怎么做?例如。使用 Symfony。

The docs提议:

$responses = [];
for ($i = 0; $i < 379; ++$i) {
    $uri = "https://http2.akamai.com/demo/tile-$i.png";
    $responses[] = $client->request('GET', $uri);
}

foreach ($client->stream($responses) as $response => $chunk) {
    if ($chunk->isFirst()) {
        // headers of $response just arrived
        // $response->getHeaders() is now a non-blocking call
    } elseif ($chunk->isLast()) {
        // the full content of $response just completed
        // $response->getContent() is now a non-blocking call
    } else {
        // $chunk->getContent() will return a piece
        // of the response body that just arrived
    }
}

但是如果在我的情况下$i &lt;= 1_000_000_000 呢?很明显,同时发送它们是没有意义的。 (而且是不可能的内存消耗。)

我怎样才能很好地做到这一点?在我看来,在循环中获得完整响应后,我应该以某种方式添加新请求。但是怎么做呢?

$responses = (static function () use ($client) {
    for ($i = 0; $i < 1e5; $i++) {
        $uri = "http://localhost/test.php?id=$i";
        yield $client->request('GET', $uri);
    }
})();

foreach ($client->stream($responses) as $response => $chunk) {
    if ($chunk->isLast()) {
        // how to schedule next request?
    }
}

或者我可以用 guzzle 或 curl 轻松做到这一点?

【问题讨论】:

  • 我这样做的方式是分批。这一切都应该通过 CLI 而不是在网页中完成,否则您只是在问问题。无论如何,让您的脚本连接到数据存储并请求尚未处理的n 项目。处理完每一个后,在商店中将其标记为完成。让脚本调用者根据需要自动重启脚本。要么使用某种cron or a daemon 作为调用者。如果你想变得很花哨,你也可以加入队列
  • @ChrisHaas 我刚刚找到了一种使用 guzzle 的更简单的方法。我会在几分钟内发布完整的答案。简而言之,只需使用 guzzle pool:“当您希望发送的请求数量不确定时,您可以使用 GuzzleHttp\Pool 对象。” docs.guzzlephp.org/en/stable/…

标签: php symfony http request php-curl


【解决方案1】:

当您希望发送的请求数量不确定时,您可以使用GuzzleHttp\Pool 对象:https://docs.guzzlephp.org/en/stable/quickstart.html#concurrent-requests

use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use Psr\Http\Message\ResponseInterface;

$client = new Client();

$onResponse = function (ResponseInterface $response) {
    echo $response->getBody();
};
$requests = (function () use ($client, $onResponse) {
    for ($i = 0; $i < 1e3; $i++) {
        yield fn() => $client->getAsync("http://localhost/test.php?id=$i")
            ->then($onResponse);
    }
})();

(new Pool($client, $requests, ['concurrency' => 10]))->promise()->wait();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多