• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

php如何实现并发请求(代码)

php 搞代码 4年前 (2022-01-21) 15次浏览 已收录 0个评论

本篇文章给大家带来的内容是关于php如何实现并发请求(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

后端服务开发中经常会有并发请求的需求,比如你需要获取10家供应商的带宽数据(每个都提供不同的url),然后返回一个整合后的数据,你会怎么做呢?

PHP中,最直观的做法foreach遍历urls,并保存每个请求的结果即可,那么如果供应商提供的接口平均耗时5s,你的这个接口请求耗时就达到了50s,这对于追求速度和性能的网站来说是不可接受的。

这个时候你就需要并发请求了。

PHP请求

PHP是单进程同步模型,一个请求对应一个进程,I/O是同步阻塞的。通过nginx/apache/php-fpm等服务的扩展,才使得PHP提供高并发的服务,原理就是维护一个进程池,每个请求服务时单独起一个新的进程,每个进程独立存在。

PHP不支持多线程模式和回调处理,因此PHP内部脚本都是同步阻塞式的,如果你发起一个5s的请求,那么程序就会I/O阻塞5s,直到请求返回结果,才会继续执行代码。因此做爬虫之类的高并发请求需求很吃力。

那怎么来解决并发请求的问题呢?除了内置的file_get_contentsfsockopen请求方式,PHP也支持cURL扩展来发起请求,它支持常规的单个请求:PHP cURL请求详解,也支持并发请求,其并发原理是cURL扩展使用多线程来管理多请求。

PHP并发请求

我们直接来看代码demo:

// 简单demo,默认支持为GET请求public function multiRequest($urls) {    $mh = curl_multi_init();    $urlHandlers = [];    $urlData = [];    // 初始化多个请求句柄为一个    foreach($urls as $value) {        $ch = curl_init();        $url = $value['url'];        $url .= strpos($url, '?') ? '&' : '?';        $params = $value['params'];        $url .= is_array($params) ? http_build_query($params) : $params;        curl_setopt($ch, CURLOPT_URL, $url);        // 设置数据通过字符串返回,而不是直接输出        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        $urlHandlers[] = $ch;        curl_multi_add_handle($mh, $ch);    }    $active = null;    // 检测操作的初始状态是否OK,CURLM_CALL_MULTI_PERFORM为常量值-1    do {        // 返回的$active是活跃连接的数量,$mrc是返回值,正常为0,异常为-1        $mrc = curl_multi_exec($mh, $active);    } while ($mrc == CURLM_CALL_MULTI_PERFORM);    // 如果还有活动的请求,同时操作状态OK,CURLM_OK为常量值0    while ($active && $mrc == CURLM_OK) {        // 持续查询状态并不利于处理任务,每50ms检查一次,此时释放CPU,降低机器负载        usleep(50000);        // 如果批处理句柄OK,重复检查操作状态直至OK。select返回值异常时为-1,正常为1(因为只有1个批处理句柄)        if (curl_multi_select($mh) != -1) {            do {                $mrc = curl_multi_exec($mh, $active);            } while ($mrc == CURLM_CALL_MULTI_PERFORM);        }    }    // 获取返回结果    foreach($urlHandlers as $index => $ch) {        $urlData[$index] = curl_multi_getcontent($ch);        // 移除单个curl句柄        curl_multi_remove_handle($mh, $ch);    }    curl_multi_close($mh);    return $urlData;}

在该并发请求中,先创建一个批处理句柄,然后将urlcURL句柄添加到批处理句柄中,并不断查询批处理句柄的执行状态,当执行完成后,获取返回的结果。

curl_multi 相关函数

/** 函数作用:返回一个新cURL批处理句柄    @return resource 成功返回cURL批处理句柄,失败返回false*/resource curl_multi_init ( void )/** 函数作用:向curl批处理会话中添加单独的curl句柄    @param $mh 由curl_multi_init返回的批处理句柄    @param $ch 由curl_init返回的cURL句柄    @return resource 成功返回cURL批处理句柄,失败返回false*/int curl_multi_add_handle ( resource $mh , resource $ch )/** 函数作用:运行当前 cURL 句柄的子连接    @param $mh 由curl_multi_init返回的批处理句柄    @param $still_running 一个用来判断操作是否仍在执行的标识的引用    @return 一个定义于 cURL 预定义常量中的 cURL 代码*/int curl_multi_exec ( resource $mh , int &$still_running )/** 函数作用:等待所有cURL批处理中的活动连接    @param $mh 由curl_multi_init返回的批处理句柄    @param $timeout 以秒为单位,等待响应的时间    @return 成功时返回描述符集合中描述符的数量。失败时,select失败时返回-1,否则返回超时(从底层的select系统调用).*/int curl_multi_select ( resource $mh [, float $timeout = 1.0 ] )/** 函数作用:移除cURL批处理句柄资源中的某个句柄资源    说明:从给定的批处理句柄mh中移除ch句柄。当ch句柄被移除以后,仍然可以合法地用curl_exec()执行这个句柄。如果要移除的句柄正在被使用,则这个句柄涉及的所有传输任务会被中止。    @param $mh 由curl_multi_init返回的批处理句柄    @param $ch 由curl_init返回的cURL句柄    @return 成功时返回0,失败时返回CURLM_XXX中的一个*/int curl_multi_remove_handle ( resource $mh , resource $ch )/** 函数作用:关闭一组cURL句柄    @param $mh 由curl_multi_init返回的批处理句柄    @return void*/void curl_multi_close ( resource $mh )/** 函数作用:如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流    @param $ch 由curl_init返回的cURL句柄    @return string 如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流。*/string curl_multi_getcontent ( resource $ch )

本例中使用到的预定义常量:
CURLM_CALL_MULTI_PERFORM: (int) -1
CURLM_OK: (

本文来源gaodai.ma#com搞##代!^码@网*
搞gaodaima代码

int) 0

PHP并发请求耗时对比


  1. 搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
    转载请注明原文链接:php如何实现并发请求(代码)

    喜欢 (0)
    [搞代码]
    分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址