php 如何同时执行多个 Guzzle 请求?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19520185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 19:37:42  来源:igfitidea点击:

How to perform multiple Guzzle requests at the same time?

phpcurlguzzle

提问by Martijn

I can perform single requests using Guzzle and I'm very pleased with Guzzle's performance so far however, I read in the Guzzle API something about MultiCurl and Batching.

我可以使用 Guzzle 执行单个请求,到目前为止我对 Guzzle 的性能非常满意,但是,我在 Guzzle API 中读到了一些关于 MultiCurl 和批处理的内容。

Could someone explain to me how to make multiple requests at the same time? Async if possible. I don't know if that is what they mean with MultiCurl. Sync would also be not a problem. I just want to do multiple requests at the same time or very close (short space of time).

有人可以向我解释如何同时发出多个请求吗?如果可能,异步。我不知道这是否是 MultiCurl 的意思。同步也不是问题。我只想同时或非常接近(短时间)执行多个请求。

采纳答案by Michael Dowling

From the docs: http://guzzle3.readthedocs.org/http-client/client.html#sending-requests-in-parallel

来自文档:http: //guzzle3.readthedocs.org/http-client/client.html#sending-requests-in-parallel

For an easy to use solution that returns a hash of request objects mapping to a response or error, see http://guzzle3.readthedocs.org/batching/batching.html#batching

有关返回映射到响应或错误的请求对象散列的易于使用的解决方案,请参阅http://guzzle3.readthedocs.org/batching/batching.html#batching

Short example:

简短示例:

<?php

$client->send(array(
    $client->get('http://www.example.com/foo'),
    $client->get('http://www.example.com/baz'),
    $client->get('http://www.example.com/bar')
));

回答by Bizmate

An update related to the new GuzzleHttp guzzlehttp/guzzle

与新 GuzzleHttp guzzlehttp/guzzle 相关的更新

Concurrent/parallel calls are now run through a few different methods including Promises.. Concurrent Requests

并发/并行调用现在通过几种不同的方法运行,包括 Promises..并发请求

The old way of passing a array of RequestInterfaces will not work anymore.

传递 RequestInterfaces 数组的旧方法将不再起作用。

See example here

请参阅此处的示例

    $newClient = new  \GuzzleHttp\Client(['base_uri' => $base]);
    foreach($documents->documents as $doc){

        $params = [
            'language' =>'eng',
            'text' => $doc->summary,
            'apikey' => $key
        ];

        $requestArr[$doc->reference] = $newClient->getAsync( '/1/api/sync/analyze/v1?' . http_build_query( $params) );
    }

    $time_start = microtime(true);
    $responses = \GuzzleHttp\Promise\unwrap($requestArr); //$newClient->send( $requestArr );
    $time_end = microtime(true);
    $this->get('logger')->error(' NewsPerf Dev: took ' . ($time_end - $time_start) );

Update: As suggested in comments and asked by @sankalp-tambe, you can also use a different approach to avoid that a set of concurrent request with a failure will not return all the responses.

更新:正如评论中所建议的和@sankalp-tambe 所问的,您还可以使用不同的方法来避免一组失败的并发请求不会返回所有响应。

While the options suggested with Pool is feasible i still prefer promises.

虽然 Pool 建议的选项是可行的,但我仍然更喜欢承诺。

An example with promises is to use settle and and wait methods instead of unwrap.

承诺的一个例子是使用结算和等待方法而不是解包。

The difference from the example above would be

与上述示例的不同之处在于

$responses = \GuzzleHttp\Promise\settle($requestArr)->wait(); 

I have created a full example below for reference on how to handle the $responses too.

我在下面创建了一个完整的示例,以供参考如何处理 $responses。

require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Promise as GuzzlePromise;

$client = new GuzzleClient(['timeout' => 12.0]); // see how i set a timeout
$requestPromises = [];
$sitesArray = SiteEntity->getAll(); // returns an array with objects that contain a domain

foreach ($sitesArray as $site) {
    $requestPromises[$site->getDomain()] = $client->getAsync('http://' . $site->getDomain());
}

$results = GuzzlePromise\settle($requestPromises)->wait();

foreach ($results as $domain => $result) {
    $site = $sitesArray[$domain];
    $this->logger->info('Crawler FetchHomePages: domain check ' . $domain);

    if ($result['state'] === 'fulfilled') {
        $response = $result['value'];
        if ($response->getStatusCode() == 200) {
            $site->setHtml($response->getBody());
        } else {
            $site->setHtml($response->getStatusCode());
        }
    } else if ($result['state'] === 'rejected') { 
        // notice that if call fails guzzle returns is as state rejected with a reason.

        $site->setHtml('ERR: ' . $result['reason']);
    } else {
        $site->setHtml('ERR: unknown exception ');
        $this->logger->err('Crawler FetchHomePages: unknown fetch fail domain: ' . $domain);
    }

    $this->entityManager->persist($site); // this is a call to Doctrines entity manager
}

This example code was originally posted here.

此示例代码最初发布在此处

回答by Annapurna

Guzzle 6.0 has made sending multiple async requests very easy.

Guzzle 6.0 使发送多个异步请求变得非常容易。

There are multiple ways to do it.

有多种方法可以做到。

You can create the async requests and add the resultant promises to a single array, and get the result using the settle()method like this:

您可以创建异步请求并将结果承诺添加到单个数组,并使用如下settle()方法获取结果:

$promise1 = $client->getAsync('http://www.example.com/foo1');
$promise2 = $client->getAsync('http://www.example.com/foo2');
$promises = [$promise1, $promise2];

$results = GuzzleHttp\Promise\settle($promises)->wait();

You can now loop through these results and fetch the response using GuzzleHttpPromiseallor GuzzleHttpPromiseeach. Refer to this articlefor further details.

您现在可以遍历这些结果并使用GuzzleHttpPromiseall或获取响应GuzzleHttpPromiseeach。有关更多详细信息,请参阅本文

In case if you have an indeterminate number of requests to be sent(say 5 here), you can use GuzzleHttp/Pool::batch(). Here is an example:

如果您要发送的请求数量不确定(这里说 5 个),您可以使用GuzzleHttp/Pool::batch(). 下面是一个例子:

$client = new Client();

// Create the requests
$requests = function ($total) use($client) {
    for ($i = 1; $i <= $total; $i++) {
        yield new Request('GET', 'http://www.example.com/foo' . $i);
    }
};

// Use the Pool::batch()
$pool_batch = Pool::batch($client, $requests(5));
foreach ($pool_batch as $pool => $res) {

    if ($res instanceof RequestException) {
        // Do sth
        continue;
    }

    // Do sth
}