php - Guzzle 池 : Wait for Requests

标签 php curl guzzle

是否可以让 Guzzle 池等待请求?

现在我可以动态地向池中添加请求,但是一旦池为空,guzzle 就会停止(很明显)。

当我同时处理 10 个左右的页面时,这是一个问题,因为在处理生成的 HTML 页面并添加新链接之前,我的请求数组将为空。

这是我的发电机:

$generator = function () {
  while ($request = array_shift($this->requests)) {
    if (isset($request['page'])) {
      $key = 'page_' . $request['page'];
    } else {
      $key = 'listing_' . $request['listing'];
    }

    yield $key => new Request('GET', $request['url']);                                          
  }
  echo "Exiting...\n";
  flush();
};

还有我的游泳池:

$pool = new Pool($this->client, $generator(), [
  'concurrency' => function() {
    return max(1, min(count($this->requests), 2));
  },
  'fulfilled' => function ($response, $index) {
      // new requests may be added to the $this->requests array here
  }
  //...
]);

$promise = $pool->promise();
$promise->wait();

@Alexey Shockov 回答后编辑代码:

$generator = function() use ($headers) {
  while ($request = array_shift($this->requests)) {
    echo 'Requesting ' . $request['id'] . ': ' . $request['url'] . "\r\n";

    $r = new Request('GET', $request['url'], $headers);

    yield 'id_' . $request['id'] => $this->client->sendAsync($r)->then(function($response, $index) {
      echo 'In promise fulfillment ' . $index . "\r\n";
    }, function($reason, $index) {
      echo 'in rejected: ' . $index . "\r\n";
    });
  }
};

$promise = \GuzzleHttp\Promise\each_limit($generator(), 10, function() {
  echo 'fullfilled' . "\r\n";
  flush();
}, function($err) {
  echo 'rejected' . "\r\n";
  echo $err->getMessage();
  flush();
});
$promise->wait();

最佳答案

不幸的是,您不能使用生成器做到这一点,只能使用自定义迭代器。

我准备了 a gist with the full example ,但主要思想只是创建一个迭代器,它会以两种方式改变其状态(它可以在结束后再次生效)。

psysh 中的 ArrayIterator 示例:

>>> $a = new ArrayIterator([1, 2])
=> ArrayIterator {#186
     +0: 1,
     +1: 2,
   }
>>> $a->current()
=> 1
>>> $a->next()
=> null
>>> $a->current()
=> 2
>>> $a->next()
=> null
>>> $a->valid()
=> false
>>> $a[] = 2
=> 2
>>> $a->valid()
=> true
>>> $a->current()
=> 2

考虑到这个想法,我们可以将这样的动态迭代器传递给 Guzzle 并让它完成工作:

// MapIterator mainly needed for readability.
$generator = new MapIterator(
    // Initial data. This object will be always passed as the second parameter to the callback below
    new \ArrayIterator(['http://google.com']),
    function ($request, $array) use ($httpClient, $next) {
        return $httpClient->requestAsync('GET', $request)
            ->then(function (Response $response) use ($request, $array, $next) {
                // The status code for example.
                echo $request . ': ' . $response->getStatusCode() . PHP_EOL;
                // New requests.
                $array->append($next->shift());
                $array->append($next->shift());
            });
    }
);
// The "magic".
$generator = new ExpectingIterator($generator);
// And the concurrent runner.
$promise = \GuzzleHttp\Promise\each_limit($generator, 5);
$promise->wait();

正如我之前所说,完整示例在 the gist,与 MapIteratorExpectingIterator

关于php - Guzzle 池 : Wait for Requests,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42754389/

相关文章:

php - 调用未定义的方法 Goutte\Client::setClient()

php - 在 symfony/goutte 中加入 URL

php - PDO更新仅更新一行

php - 为什么我无法对 API 的响应进行 json_decode?

php - 使用 fread 方法扩展 SplFileObject

PHP 与 neo4j 的连接 "cURL error 7"

android - 通过 java/android 代码设置 Nest 字段值时遇到问题

c# - 如何将包含--data-urlencode 的curl 转换为HttpClient 调用?

php - magento $order->getAllItems() 返回两次相同的项目

php - 包含 PHP,当包含的 PHP 代码用于不同目录中的文件时不起作用