【PHP基础学习】—PHP异步非阻塞的实现方法

本文介绍PHP中实现异步非阻塞处理的方法,包括FastCGI的非阻塞方法、fsockopen()+stream_set_blocking()、cURL执行异步请求、使用Gearman/Swoole框架、缓存和队列及pcntl_fork()等,并对比了它们的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

由于PHP本身是一种单进程的语言,每次请求在apache都是一个进程,在Nginx和fastCGI里面每个请求时一个单独的worker线程,而且在各个服务器里面的请求都是阻塞的,所以有些大批量的复杂逻辑或文本处理会导致请求响应时间很长,这里我们就要考虑让PHP实现异步非阻塞的做法,已达到减少响应时间的目的

一、各种实现方法

1、FastCGI的非阻塞方法:fastcgi_finish_request()
在PHP5.3.3版本之后,不管是Nginx还是Apache服务器,只要运行在FastCGI模式下,均可使用该方法,官方解释的作用是冲刷(flush)所有响应的数据给客户端。
boolean fastcgi_finish_request ( void )
此函数冲刷(flush)所有响应的数据给客户端并结束请求。 这使得客户端结束连接后,需要大量时间运行的任务能够继续运行。
用法:可以在读写大文件、循环更新数据库等不影响结果的操作之前,执行该函数,把结果返回给客户端,php会继续执行下面的逻辑而不影响客户端的响应时间。

2、fsockopen()+stream_set_blocking()方法:
fsockopen()方法可以打开一个网络连接或Unxi套接字连接,stream_set_blocking()方法可以为资源流设置非阻塞或者阻塞模式,
使用fsockopen()打开一个网络连接或者一个Unix套接字连接,再用stream_set_blocking()设置资源成非阻塞模式请求,则该资源请求会是非阻塞的:
bool stream_set_blocking ( resource $stream , int $mode )
注:$mode=0则是非阻塞的,1则是阻塞的模式。
用法:

3、使用cURL执行异步请求:
cURL除了我们通常使用的curl_init来初始化和发送post和get请求之外,还可以使用curl_multi_init()方法来实现异步请求,其原理是使用系统的select这个多路I/O复用机制来异步发送请求
通常的用法:

异步用法:

4、使用Gearman/Swoole等PHP异步扩展或框架

5、使用缓存和队列
通常复杂的处理逻辑,我们可以将参数推入队列,如redis或kafka的队列服务,开启一个消费进程去处理队列事务。
如redis服务的list结构,在之前篇章有过说明。

6、使用pcntl_fork()
在PHP4.1.0版本之后都支持了该函数,使用前需要安装支持pcntl扩展并添加支持。
官方文档:在当前进程当前位置产生分支(子进程),这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同
说明:int pcntl_fork ( void )
成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0;
失败时,在父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。
用法:

二、优劣对比

并发IO问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接Fork进程,到Worker进程池/线程池,到现在的异步IO、协程。阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。现在网络的日益发展,对响应时间和处理并发的要求越来越高,所以异步非阻塞的需求也越来越多,优点也显而易见:
1、非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程,能及时返回响应,减少响应时间
2、高并发,同步阻塞IO模型的并发能力依赖于进程/线程数量,响应时间的下降可以带来更多的并发能力

当然,异步非阻塞又存在缺点:
1、启动大量进程会带来额外的进程调度消耗。非阻塞模式下,如果大量线程已经返回响应而仍然在执行计算操作,会使CPU利用率不可控的增高;
2、这种模型严重依赖进程的数量解决并发问题,一个客户端连接就需要占用一个进程,工作进程的数量有多少,并发处理能力就有多少。操作系统可以创建的进程数量是有限的;
3、过多的异步和多线程模型会造成编码困难或线程混乱,如出现大量僵尸进程等。


三、总结

1、一般情况下,我们不赞成用异步回调的方式去做功能开发,传统的PHP同步方式实现功能和逻辑是最简单的,也是最佳的方案。像node.js这样到处callback,只是牺牲可维护性和开发效率;
2、有些时候很适合用异步,比如FTP、聊天服务器,smtp,代理服务器等等此类以通信和读写磁盘为主,功能和业务逻辑其次的服务器程序
3、异步非阻塞和多线程模型推荐:
(1)swoole框架:fpm里,通过swoole_client把url发送到swoole的server,swoole_server天然支持并行请求,把汇总的结果返回到fpm;
这也是当下PHP最火的异步多线程框架,可以了解一下韩天峰的文章:http://rango.swoole.com/
(2)recoil框架:https://github.com/recoilphp/recoil

参考文章:

1、http://rango.swoole.com/archives/508
2、https://www.kancloud.cn/fage/swoole_extension/691431
3、https://www.awaimai.com/660.html

PHP实现异步非阻塞处理机制,主要依赖于其运行环境、扩展以及编程模型的优化。PHP 本身是单线程、同步阻塞的语言,但在实际开发中,可以通过多种方式实现异步非阻塞的效果,从而提升系统性能和并发处理能力。 ### 异步非阻塞实现方式 1. **FastCGI 的非阻塞方法(`fastcgi_finish_request()`)** 在 PHP-FPM 环境下,可以使用 `fastcgi_finish_request()` 函数提前结束 HTTP 响应,使客户端可以立即收到响应,而服务器继续在后台执行后续逻辑。这种方式适用于需要异步处理日志记录、邮件发送等操作的场景。 ```php echo "Response sent to client"; fastcgi_finish_request(); // 后续代码继续执行,但客户端已收到响应 ``` 2. **使用 `fsockopen()` + `stream_set_blocking()`** 通过创建非阻塞的 socket 连接,可以在等待响应的情况下发起外部请求。此方法适合需要与外部服务通信但关心其结果的场景[^1]。 3. **cURL 多请求异步执行** 使用 `curl_multi_init()` 可以同时发起多个 cURL 请求,并通过非阻塞方式处理网络 I/O,从而实现异步 HTTP 请求[^1]。 4. **使用异步框架(如 Swoole、ReactPHP、Amp)** 这些框架基于事件驱动和协程模型,提供了完整的异步非阻塞处理能力。例如,Swoole 提供了协程、异步 I/O、定时器等功能,使得 PHP 可以构建高性能的异步服务。 5. **使用 Gearman 或 Redis 队列实现异步任务分发** 将耗时任务放入队列中由工作进程异步处理,主流程可以快速返回响应,适用于异步日志、批量数据处理等场景。 6. **使用 `pcntl_fork()` 创建子进程** 在 CLI 模式下,可以通过 `pcntl_fork()` 创建子进程来执行异步任务,主进程可立即返回结果。 ### 异步非阻塞处理机制 PHP异步非阻塞处理机制主要围绕以下几个核心概念: - **协程(Coroutine)**:协程是一种用户态的轻量级线程,可以在单线程中实现多个任务的调度。例如,Swoole 和 Amp 框架都基于协程实现异步编程模型[^2]。 - **事件循环(Event Loop)**:异步框架通常依赖事件循环来监听和处理 I/O 事件,如网络请求、定时器等。ReactPHP 和 Amp 都提供了强大的事件循环机制[^2]。 - **连接池(Connection Pool)**:在数据库访问中,连接池可以避免频繁创建和销毁连接带来的性能损耗。例如,AMPHP 提供了异步非阻塞的 MySQL 客户端连接池[^2]。 ### 实际应用示例(Swoole 协程) ```php go(function () { $client = new Swoole\Coroutine\Http\Client('example.com', 80); $client->get('/', function ($client) { echo $client->body; }); $client->close(); }); ``` 上述代码使用 Swoole 协程发起异步 HTTP 请求,主线程会被阻塞,适用于高并发场景。 ### 总结 PHP 虽然默认是同步阻塞的,但通过 FastCGI、异步框架、协程、事件循环等方式,可以实现高效的异步非阻塞处理机制。在选择实现方式时,应根据具体业务需求和部署环境进行合理选择。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值