【问题标题】:Using Guzzle to perform batch request使用 Guzzle 执行批处理请求
【发布时间】:2020-11-20 14:55:39
【问题描述】:

我正在做一个项目,我需要使用 Guzzle 对端点执行 2000 个异步请求,并且每次我需要更改 url 参数中的 ID。

端点如下所示:http://example.com/api/book?id=X

我尝试使用 for 循环来做到这一点,唯一的问题是它不是异步的。执行此类任务的更有效方法是什么?

public function fetchBooks () {
    $client = new Client();
    $responses = [];
    for ($i=1; $i < 2000; $i++) { 
        $response = $client->post('https://example.com/api/book?id=' . $i);
        array_push($responses, json_decode($response->getBody(), true));
    }
    return $responses;
}

【问题讨论】:

    标签: php laravel guzzle


    【解决方案1】:

    在您的情况下,我将首先检查其余 api 是否公开了一个端点,这使得一次发送所有条目的数据成为可能。在这种情况下,如果允许附加的条目数量有限制,您可能只需要一个调用,或者可能需要几个调用。

    如果不是这样,那么没有别的办法,那就调用其余端点2000次。你已经说过了。您的调用是同步的,效率很低,因为它会等待每个请求完成,然后再开始下一个请求。

    为避免这种情况,请改用异步函数$client-&gt;postAsync。这将使并发运行请求成为可能。每个请求都会返回一个承诺。基本上,您希望等待所有承诺解决并继续执行程序。为此,将所有 Promise 存储在一个数组中,并使用 Promise\settle($promises)-&gt;wait();Promise\unwrap($promises);,如果您希望在发生错误时停止执行。

    代码可能如下所示:

    <?php
    use GuzzleHttp\Client;
    use GuzzleHttp\Promise;
    
    public function fetchBooks () {
        $client = new Client();
        $promises = [];
        for ($i=1; $i < 2000; $i++) { 
            $promise = $client->postAsync('https://example.com/api/book?id=' . $i);
            array_push($promises, $promise);
        }
        
        $results = Promise\settle($promises)->wait();
     
        $responses = [];
    
        foreach ($results as $result) {
          array_push($responses, json_decode($result->getBody(), true));
       }
    
       return $responses;
    }
    
    
    ?>
    

    【讨论】:

      【解决方案2】:

      @wasserholz 的回答是正确的,仍然使用 2 array_push(占用更多内存从而使 api 变慢,所以改为使用 []),并且可以减少一个 array_push。

      use GuzzleHttp\Psr7\Response;
      
      $responses = []; 
      $client = new \GuzzleHttp\Client([
                  'base_uri' => 'https://example.com'
              ]);
                      
              $requests = function () use ($client) {
                  for ($i = 0; $i < 2000; $i++) {
                      yield function() use ($client,$i) {
                          return $client->postAsync('/api/book?id=' . $i);
                      };
                  }
                  
              };
          
              $pool = new \GuzzleHttp\Pool($client, $requests(),[
                  'concurrency' => 5,
                  'fulfilled' => function (Response $response, $index) use (&$responses) {
                      // if ($response->getStatusCode() == 200) {
                            $responses[] = json_decode($response->getBody(), true);
                      // }
                      print_r($responses); // this will have all the responses 
                  },
                  'rejected' => function (\GuzzleHttp\Exception\RequestException $reason, $index) {
                      // dd($reason); //you can store it in laravel logs
                  },
              ]);
          
              $pool->promise()->wait();
              return response()->json($responses);
      

      【讨论】:

      • 这给了我一个空洞的回应。你能修改你的解决方案吗?
      • 在已完成的块之外,响应不可访问,所以如果您在外面使用它将是空的
      • 答案在这里更新以展示如何在外面使用块,所以它对你有用吗?
      猜你喜欢
      • 2021-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      • 2018-08-10
      • 2023-02-09
      • 2013-09-19
      相关资源
      最近更新 更多