php接口优化 使用curl_multi_init批量请求

dafenqi
2023-12-04 / 1 评论 / 81 阅读 / 正在检测是否收录...

需求:一个接口里请求了多个接口(方法),查询速度缓慢,每个请求2s,加起来11、12s。
实现:PHP中的curl_multi一类函数可以实现同时请求多个url,而不是一个一个依次请求,这就类似一个进程实现了多个线程的功能,最终接口请求耗时优化到2s,即查询耗时最长的那次是最终的查询时长。

<?php

class XClass extends BaseSys
{
  public function index()
  {
    $rs = [];
    $local_url = "当前请求地址";
  
    $urlArr = [];
    $paramsArr = [];
    $params = $_POST;
    $curAction = [
        ['name'=>'getANum','bool'=>''],
        ['name'=>'getCNum','bool'=>true],
        ['name'=>'getCNum','bool'=>false],
        ['name'=>'getLNum','bool'=>''],
        ......
    ];//接口名、参数
    foreach ($curAction as $key => $item) {
        $urlArr[] = $local_url . "XClass/".$item["name"];
        $subparams = $params;
        $subparams["bool"] = $item["bool"];
        $subparams["isMutil"] = 1;
        $paramsArr[] = $subparams;
    }
    $contentArr = $this->mutil_curl($urlArr, $paramsArr);
    foreach ($contentArr as &$item) {
        $rs[] = json_decode($item,true);
    }
    return $rs;
  }
  
  public function getCNum($isNew = false)
  {
      //TODO
      
      if (isset($_POST["isMutil"])) {//mutil_curl并发请求结果
          exit($json_encode($rs, JSON_UNESCAPED_UNICODE) . '');
      }
      return $rs;
  }

    
  
  /**
   * 多url同时访问curl操作封装,一般用于内部并行数据查询
   * $urlArr 要访问的网址集合,get方法的时候请在此网址上直接带上参数
   * $paramsArr 要post的数据集合
   */
  public function mutil_curl($urlArr, $paramsArr = null, $timeout = 60)
  {
      $contentArr = [];
      $num = 0;
      $len = count($urlArr)-1;
      foreach ($urlArr as $k => $url) {
          if($num == 0){
              $subrulArr = [];
          }
          $subrulArr[$k] = $url;
          $num++;
          if($num == 16 || $len == $k){
              $subcontentArr = $this->_do_mutil_curl($subrulArr, $paramsArr);
              foreach ($subcontentArr as $subkey => $subvalue) {
                  $contentArr[$subkey] = $subvalue;
              }
              $num = 0;
          }
      }
      return $contentArr;
  }
  
  public function _do_mutil_curl($urlArr, $paramsArr = null, $timeout = 60)
  {
      set_time_limit($timeout);
      // curl 批处理
      $mh = curl_multi_init();
      // 保存单个句柄
      $handles = [];
      // 向 curl 批处理会话 中添加单独的 curl句柄
      foreach ($urlArr as $k => $url) {
  
          $ch = curl_init(); // 初始化curl并设置链接
          curl_setopt($ch, CURLOPT_URL, $url);
          curl_setopt($ch, CURLOPT_HEADER, 0);
          curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
          // 设置是否为post传递
          curl_setopt($ch, CURLOPT_POST, !empty($paramsArr));
          // 对于https 设定为不验证证书和host
          curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
          curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//设置是否返回信息
  
          if (!empty($paramsArr)) {
              $params = $paramsArr[$k];
              if ($params) {
                  if (is_array($params)) {
                      $params = http_build_query($params);
                  }
                  // POST 数据
                  curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
                  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
              }
          }
          $handles[$k] = $ch;
          curl_multi_add_handle($mh, $handles[$k]);
      }
  
      $active = null;
      $contentArr = [];
  
      do {
          $mrc = curl_multi_exec($mh, $active);
      } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  
  
      while ($active and $mrc == CURLM_OK) {
          if (curl_multi_select($mh) != -1) {
              do {
                  $mrc = curl_multi_exec($mh, $active);
              } while ($mrc == CURLM_CALL_MULTI_PERFORM);
          }
      }
  
  
      // 循环输出 大小以及地址
      foreach ($handles as $i => $handle) {
          // 内容
          $content = curl_multi_getcontent($handle);
          $contentArr[$i] = $content;
          curl_multi_remove_handle($mh, $handle);
      }
  
      curl_multi_close($mh);
      return $contentArr;
  }
  
PS:这里为了方便显示,把mutil_curl()和_do_mutil_curl()放在同一个类中,实际上它们是放在一个工具类里,方便调用。
0

评论 (1)

取消
  1. 头像

    [...]具体应用案例: php接口优化 使用curl_multi_init批量请求[...]

    回复
歌曲封面
0:00