php实现异步轮询

article/2025/10/14 8:24:10

文章目录

    • 一、前言
    • 二、工欲善其事
      • 1、curl是伪异步请求
      • 2、鸟哥推荐的方法中有curl
    • 三、异步轮询(fsockopen)
      • 1、模拟异步轮询的demo
      • 2、响应页面代码
      • 3、测试结果
      • 4、fsockopen(): unable to connect to 错误
    • 四、问题以及反思
      • 1、无法调试返回
      • 2、占用进程
      • 3、最佳方式
      • 4、python,酸,真酸

一、前言

      如题所示,对于phper来说,异步轮询总是会觉得很麻烦,在不考虑workmanswoole的情况下,对了还有个Guzzlephp总是被人诟病的就是多线程异步IO问题了,刚好博主最近有这个需求,下面咱们来一起研究下怎么实现原生的异步轮询。

二、工欲善其事

      既然是要做异步,博主的脑海里第一时间浮现的是curl的方式,我们平时对于一些外部请求,用的最多的就是curl方式,还可以避开https的证书验证,那么curl的方式符合需求吗?

1、curl是伪异步请求

      在不断的百度中,发现大家虽然有用curl进行异步请求的,但是不管是curl还是curl_multi 都需要把整个请求池所有请求处理完毕,把所有响应报文拿到,才会继续往下走的。虽然看起来像异步,但是实际上是同步阻塞的。

参考 : 关于 php 通过 curl 的伪异步方式抓取数据,下面这种 curl 方式和普通的 curl 同步请求有什么区别?

2、鸟哥推荐的方法中有curl

鸟哥博文:PHP实现异步调用方法研究

      这里其实鸟哥给出了最佳的方式,不过这个curl鸟哥也提了一下,说是最小超时时间是1s,其实看到这里大家也都明白了,curl并不是比较好的方式,不过咱们还是研究下这个最小1s的问题,因为博主记得可以设置毫秒级的超时来着:

function _curl($url) {$ch = curl_init();curl_setopt($ch,CURLOPT_URL,$url);curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);curl_setopt($ch, CURLOPT_NOSIGNAL, true);    //注意,毫秒超时一定要设置这个curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200); //超时时间200毫秒$result = curl_exec($ch);curl_close($ch);return $result;
}

      通过这种写法,是可以实现毫秒级的,不过想要得到什么,那就要失去什么,代价是这样一来, 就会有一个隐患, 那就是DNS解析将不受超时限制了。这样一来,最好是老老实实的设置CURLOPT_TIMEOUT为1。

参考:Curl的毫秒超时的一个"Bug"

      OK,那这里咱们就选择用fsockopen的方式来实现异步轮询,具体请看下文。

三、异步轮询(fsockopen)

1、模拟异步轮询的demo

想要模拟异步轮询,那肯定是要有两个请求方法的,这里我们使用test1.phptest2.php两个页面:

test1页面代码:

<?phpfunction request_by_fsockopen($url,$post_data=array()){$url_array = parse_url($url);$hostname = $url_array['host'];$port = isset($url_array['port']) ? $url_array['port'] : 80;$query = isset($url_array['query']) ? $url_array['query'] : '';$requestPath = isset($url_array['path']) ? $url_array['path'] . "?" . $query : $url;// http 协议的话是 $fp = fsockopen("ssl://localhost", 443, $errno, $errstr);$fp = fsockopen($hostname, $port, $errno, $errstr, 10);if (!$fp) {echo "$errstr ($errno)";return false;}$method = "GET";if (!empty($post_data)) {$method = "POST";}$header = "$method $requestPath " . "HTTP/1.1\r\n";$header .= "Host: $hostname\r\n";    // POSTif (!empty($post_data)) {$_post = [];foreach ($post_data as $k => $v) {$_post[] = $k . "=" . urlencode($v);//必须做url转码以防模拟post提交的数据中有&符而导致post参数键值对紊乱}$_post = implode('&', $_post);// send request$header .= "Content-Type: application/x-www-form-urlencoded\r\n";//POST数据$header .= "Content-Length: " . strlen($_post) . "\r\n";//POST数据的长度$header .= "Connection: Close\r\n\r\n";//长连接关闭$header .= $_post; //传递POST数据} else {$header .= "Connection: Close\r\n\r\n";//长连接关闭}stream_set_blocking($fp, 0); //非阻塞,true也就是1的时候,代表阻塞stream_set_timeout($fp, 1);//响应超时时间(S),读取流的超时时间fwrite($fp, $header);//-----------------调试代码区间-----------------//如果打开注释,则异步请求变成同步请求,效果还不如curl$html = '';
//    while (!feof($fp)) {
//        $html .= fgets($fp, 1024);
//    }//-----------------调试代码区间-----------------usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499fclose($fp);//解析返回的内容,返回的并不是直接的json,所以需要正则匹配到json,然后处理/*preg_match('/\{(.*)\}/s', $html, $matches);$data = json_decode($matches[0], true);print_r($data);*/$status = time();return $status;  //获取这个值,然后return
}function test()
{
// 这个$data是为了模拟post请求的参数,如果是get请求,就不需要$data参数了$data = array('xxx' => 'xxxx',);$status = request_by_fsockopen('http://localhost/test22.php', $data);   //模拟postecho $status;
}test();
echo '是否堵塞';
echo "结束时间".time().'<br/>';?>

解释:
      这段代码主要是打印了一些时间,然后调用咱们写好的函数来实现fsockopen的异步去请求。$data数组是为了模拟post请求,如果是get请求的话就不需要传这个数组了。

注意:

(1) 拼接header头的话,需要注意用的是哪个版本的http,选择不同的http版本,拼接header部分是有差异的,博主这里拼接的是http1.1的头部,如果是其他版本的,参考:fsockopen与HTTP 1.1/HTTP 1.0

(2) 需要设置 非阻塞访问模式

stream_set_blocking($fp, 0); //非阻塞,true也就是1的时候,代表阻塞stream_set_timeout($fp, 1);//响应超时时间(S),读取流的超时时间

(3) 注释有个代码调试区间,当我们打开注释的时候,相当于要获取该请求的返回值,那么此时就从异步变成同步了,需要注意下。
(4) 如果要获取请求内容的话,fsockopen返回的响应需要用正则匹配json部分内容,参考代码上的注释即可。

2、响应页面代码

<?php
set_time_limit(0);  //表示长时间链接运行,不限制运行时间
ignore_user_abort(true);//设置与客户机断开是否会终止执行
//开启该参数之后,该PHP脚本将一直处于执行的状态,代价就是占用进程
//fastcgi_finish_request();//FastCGI模式独有,冲刷(flush)所有响应的数据给客户端。提高请求的处理速度//收到请求后,sleep,然后写入到日志
function b()
{$i = 0;do {$message = "开始时间:" . time();sleep(5);$request = $_SERVER['REQUEST_METHOD'];$message .= "请求方式:" . $request;$message .= "<br/>sleep结束" . time() . "\n";//FILE_APPEND参数是为了不覆盖前面的内容file_put_contents("E:\log.txt", $message, FILE_APPEND);$i+=1;}while($i<5);
}
// 调用b方法
b()

解释: 这个页面是请求页面,我们这里用sleep模拟阻塞,用do{}while()方式来模拟轮询,将每次的时间写入到日志,方便对比查看。

注意:
(1) 页面顶部设置set_time_limit(0);参数,异步请求的场景就是比较耗时的场景,因此我们这里要防止超时问题。
(2) 设置ignore_user_abort(true);防止客户端断开之后,页面就停止运行了

3、测试结果

(1) 页面上访问test1.php,返回:

开始时间:1575978768
1575978768是否堵塞结束时间1575978768

此时可以看到请求是很顺畅的就下来了,没有阻塞。

(2) 打印log.text文件:

$ tail -f log.txt开始时间:1575978769请求方式:POST<br/>sleep结束1575978774
开始时间:1575978775请求方式:POST<br/>sleep结束1575978780
开始时间:1575978780请求方式:POST<br/>sleep结束1575978785
开始时间:1575978785请求方式:POST<br/>sleep结束1575978790
开始时间:1575978790请求方式:POST<br/>sleep结束1575978795

      这里我们看到,确实是轮询了5次,每次都sleep了5s,但是并没有影响到咱们主程序的运行,yes,就是它了。

4、fsockopen(): unable to connect to 错误

如果在测试的时候,出现这个提示,解决方案是:

把对应的url地址:http://xxx.xxx.com
改为
xxx.xxx.com

      然后再去调用fsockopen,记得port设置为80(默认是-1),就可以正常访问了

四、问题以及反思

虽然我们这里已经完成了自己的需求,但是这样的代码是不美观而且局限性很大的,而且总觉得代码过于冗余。。

1、无法调试返回

      我们在代码里也注释过了,当我们需要调试的时候,这个异步就变成了同步,那就毫无意义了,总有一些场景是需要返回值的,很明显fsockopen还是不够完美

2、占用进程

      这个是博主自己的想法,因为要使用这种方式,那就代表它必须要占用一个进程来不停的执行这些逻辑,页面设置了不会超时和防止客户端断开停止运行,不知道这样会不会对性能有什么大的影响。。

3、最佳方式

      如果大家有时间的话,强烈推荐使用workerman,如果使用了fsockopen,这个只是讲异步发出去了,但是并没有返回回来!如果你要异步处理,就用workerman.当然swoole也可以的,但是呢,这个有C语言的,一些报错信息是C的。你会C你也可以用这个(PS:不会C也可以的!)。workerman入门比较简单,推荐的话就是:

熟悉TP框架就用workman,TP5已经集成了workman。熟悉laravel就用swoole,因为扩展安装十分方便。

4、python,酸,真酸

在这里插入图片描述
      这是博主最近写的python脚本,我滴妈啊,就引用了两个库,就实现了异步请求,还有多进程???酸,实在是酸,啥也不说了,必须赶紧学会swoole我们php也不差,主要是博主菜,对,一定是这样的!

      建议大家是早点掌握workman或者swoole,高并发和多线程早就成了业界公认的高手标准,咱们得跟上潮流不是,加油啊各位!

end


http://chatgpt.dhexx.cn/article/VMwarSu5.shtml

相关文章

java 轮询请求_使用RxJava来实现网络请求轮询功能

原标题:使用RxJava来实现网络请求轮询功能 近日有媒体报道称,腾讯重金入股永辉超市旗下生鲜超市超级物种,目前交易已经完成。受此刺激,永辉超市股价迅速涨停,午后临时停牌。若此举成行,超级物种将更有底气对垒阿里巴巴的盒马鲜生,生鲜商超的新零售市场将展开激烈争战。 …

android轮询

目录 轮询实现方案&#xff1a; Timer Handler RxJava 1.Interval 2.repeatWhen 轮询实现方案&#xff1a; 方案一&#xff1a; Timer Thread 实现思路&#xff1a;使用timer定时执行TimerTask 缺点&#xff1a;如果有异步任务&#xff0c;下次任务开始执行时需要判断…

nginx轮询

创建容器1&#xff1a; docker create -it --name zyr1 centos:7 /bin/bash docker start zyr1 进入容器&#xff1a; docker exec -it zyr1 /bin/bash 安装ipconfig命令 yum provides ifconfig 安装nginx依赖 yum -y install openssl openssl-devel prce-devel zlib z…

python 轮询mysql_python 轮询

1. 轮询 三天之后,小钱才拿到这个快递 总结 快递不能及时的传达 小钱儿 - 卒 客户端浪费极大资源 老程头儿 -痴呆 资源浪费也很严重 HTTP无法跟踪定义客户端 无状态 2. 长轮询 缺陷: 消息实时性不高 传达室茶室的资源有限 占用资源 客户端线程资源占用 3. 长连接 总结 占用的空…

java 轮询http_HTTP轮询模型

HTTP轮询模型 长短轮询 http协议是一种client-server模型的应用层协议&#xff0c;这种c-s的模式虽然大多数情况都能满足需求&#xff0c;但是某些场景也需要服务端能够将一些信息实时的推送到客户端&#xff0c;即实现服务器向客户端推消息的功能。 比如&#xff1a; 配置管理…

七种轮询介绍(后附实践链接)

我有一个朋友&#xff5e; 做了一个小破站&#xff0c;现在要实现一个站内信web消息推送的功能&#xff0c;对&#xff0c;就是下图这个小红点&#xff0c;一个很常用的功能。 不过他还没想好用什么方式做&#xff0c;这里我帮他整理了一下几种方案&#xff0c;并简单做了实现…

linux cgroup 死循环,Linux CGroup 基础

CGroup V1 1. CGroup 概念Task: 任务&#xff0c;也就是进程&#xff0c;但这里的进程和我们通常意义上的 OS 进程有些区别&#xff0c;在后面会提到。 CGroup: 控制组&#xff0c;一个 CGroup 就是一组按照某种标准划分的Tasks。这里的标准就是 Subsystem 配置。换句话说&…

linux cgroup 原理,Cgroup框架的实现

CGoup核心主要创建一系列sysfs文件&#xff0c;用户空间可以通过这些节点控制CGroup各子系统行为&#xff0c;以及各子系统模块根据参数。在执行过程中或调度进程到不同CPU上&#xff0c;或控制CPU占用时间&#xff0c;或控制IO带宽等等。另外&#xff0c;在每个系统的proc文件…

CGroup的原理和使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、主要功能二、基本概念三、cgroups子系统介绍四、cgroups 层级结构五、数据结构 前言 Linux CGroup全称Linux Control Group&#xff0c; 是Linux内核的一个…

Linux cgroup介绍

本文参考网上一些资料&#xff0c;结合实际应用&#xff0c;简要介绍一下cgroup。 为什么要有cgroup Linux系统中经常有个需求就是希望能限制某个或者某些进程的分配资源。也就是能完成一组容器的概念&#xff0c;在这个容器中&#xff0c;有分配好的特定比例的cpu时间&#…

漫谈cgroup

什么是cgroup cgroup 是linux内核的一个功能&#xff0c;用来限制、控制与分离一个进程组的资源&#xff08;如CPU、内存、磁盘I/O等&#xff09;。它是由 Google 的两位工程师进行开发的&#xff0c;自 2008 年 1 月正式发布的 Linux 内核 v2.6.24 开始提供此能力。 cgroup …

容器中的Cgroup

文章目录 容器中的CgroupCgroup概念容器化两个关键核心现代容器化带来的优势什么是Cgroup Cgroup的一些测试测试CPU和内存使用情况CPU 周期限制 CPU Core 控制CPU 配额控制参数的混合使用内存限额Block IO 的限制bps 和 iops的限制 容器中的Cgroup Cgroup概念 容器化两个关键…

Cgroup 资源配置

目录 一、Cgroup定义 二、使用stress压力测试工具测试cpu和内存状态 1、创建一个dockerfile文件 2、创建镜像 3、创建容器 ①创建容器 ②、创建容器并产生10个子函数进程 三、CPU 周期 1、实现方案 2、实验 四、CPU Core控制 五、docker build 一、Cgroup定义 cg…

cgroup资源配置

一、cgroup介绍二、利用stress 压力测试工具来测试三、CPU控制1、仅用率控制&#xff08;权重&#xff09;2、周期限制方法一&#xff1a;在命令行里直接设置方法二&#xff1a;创建容器后&#xff0c;关闭容器在文件里直接修改方法三&#xff1a;进入容器查看 3、cpu核心数4、…

【CGroup原理篇】3. CGroup使用指南

写在前面 这里先从整体上概述cgroup的创建,挂载,参数配置和卸载,后面的章节中会一一介绍每个子系统的详细使用方法和使用案例。 一、使用Linux命令管理CGroup 1.1挂载cgroup临时文件系统 mount -t tmpfs cgroup_root /sys/fs/cgroup 1.2 创建挂载层级需要的目录 mkdir /sy…

Linux CGroup 原理

Linux CGroup 原理 1、CGroup简介 cgroups是Linux下控制一个&#xff08;或一组&#xff09;进程的资源限制机制&#xff0c;全称是control groups&#xff0c;可以对cpu、内存等资源做精细化控制。 开发者可以直接基于cgroups来进行进程资源控制&#xff0c;比如8核的机器上…

LINUX CGROUP总结

简介: Linux CGroup全称Linux Control Group&#xff0c; 是Linux内核的一个功能&#xff0c;用来限制&#xff0c;控制与分离一个进程组群的资源&#xff08;如CPU、内存、磁盘输入输出等&#xff09;。这个项目最早是由Google的工程师在2006年发起&#xff08;主要是Paul Men…

cgroup 简介

cgroup 的功能在于将一台计算机上的资源&#xff08;CPU&#xff0c;memory&#xff0c;network&#xff09;进行分片&#xff0c;来防止进程间不利的资源抢占。 术语 cgroup&#xff1a;关联一组 task 和一组 subsystem 的配置参数。 一个 task 对应一个进程&#xff0c;cg…

cgroup基础介绍

一项新概念的产生&#xff0c;必然有其原因&#xff0c;cgroup也不例外&#xff0c;最初由谷歌工程师Paul Menage和Rohit Seth提出【1】&#xff1a;因为计算机硬件能力越来越强大&#xff0c;为了提高机器的使用效率&#xff0c;可以在同一台机器上运行不同运算模型的工作。开…

深入浅出cgroup

一、什么是cgroup Cgroup是linux内核用来控制系统资源的机制&#xff0c;它将操作系统中的所有进程以组为单位划分&#xff0c;给这一组进程定义对某一类资源特定的访问权限。Cgroup用子系统&#xff08;subsystem&#xff09;来描述所能控制的系统资源&#xff0c;子系统具有多…