一、概念
fastcgi_finish_request函数主要是用来,将已经处理的数据返回给客户端,并结束请求,同时在后台继续处理fastcgi_finish_request函数后面的任务。格式如下:boolean fastcgi_finish_request ( void )
返回值
成功时返回 TRUE, 或者在失败时返回 FALSE。
需要注意以下几点在运行完函数fastcgi_finish_request后,虽然结束了客户端的请求,但是仍然需要占用php-fpm进程处理后续任务,如果任务特别耗时,这样就会带来一个问题,php-fpm进程都被占用,当请求再次到来的时候,就会出现网关错误。
当以命令行的模式,是没法调用fastcgi_finish_request函数的。
在fastcgi_finish_request函数任务完成之前,会一直锁定session,这样会导致后续程序处理等待状态。幸运的是,针对这个问题是有办法解决的,即在耗时的任务之前,调用session_write_close函数,调用函数session_write_close后,仍然可以读取session,只是不能再对session进行修改或是新增操作。
在使用session_write_close函数之前,使用相同的header和cookie分别发起请求,结果如下
此时,可以看到有两个进程,占用着同一个session文件
在使用session_write_close函数之后,使用相同的header和cookie分别发起请求,结果如下
可以看出,因为开启了session,使用session_write_close函数之前,第二次请求被阻塞了,使用session_write_close函数之后就不会阻塞了。
程序如下:session_start();
$_SESSION['count'] += !isset($_SESSION['count']) ? 0 : 1;
echo 'A:curTime : ', date("Y-m-d H:i:s"), "\n";
//session_write_close();
var_dump(fastcgi_finish_request()); /* 响应完成, 关闭连接 */
/* 记录日志 */
sleep(20);
file_put_contents('log.txt', "B:curTime:". date("Y-m-d H:i:s") . "\n", FILE_APPEND);
二、使用
当PHP运行在FastCGI模式时,PHP 提供了一个名为fastcgi_finish_request的方法。该方法可以提高请求的处理速度,因为此函数能够在将数据返回给客户端并断开与客户端的连接后,继续完成需要执行的任务。听着是不是很抓狂啊!
先来搞个简单的例子试一下,比如在页面输出当前时间,5秒后记录日志。<?php
echo "hello world\n";
echo 'A:当前时间:', date("Y-m-d H:i:s"), "\n";
var_dump(fastcgi_finish_request()); /* 响应完成, 关闭连接 */
/* 记录日志 */
sleep(5);
file_put_contents('log.txt', "B:当前时间:". date("Y-m-d H:i:s") . "\n", FILE_APPEND);
下面封装一个类,便于在项目中引入和使用,如下:class FastcigCallbk {
public static $callbacks = [];
public static $checkPass = false;
/**
* 禁止实例化
* FastcigCallbk constructor.
*/
private function __construct() {
}
/**
* 判断是否支持fastcgi
* @return bool
*/
public static function check() {
if (PHP_SAPI != 'fpm-fcgi' || ! function_exists('fastcgi_finish_request')) {
self::$checkPass = false;
}
self::$checkPass = true;
return self::$checkPass;
}
/**
* 新增
*
* @param \Closure $c
* @param null $k
*/
public static function add(\Closure $c, $k = null) {
self::$checkPass || self::check();
if (! self::$checkPass) {
throw new ExceptionBiz(Errors::ERR_SYSTEM . ';当前不支持fastcgi_finish_request');
}
if ($k) {
self::$callbacks[$k] = $c;
} else {
self::$callbacks[] = $c;
}
}
/**
* 删除
*
* @param $k
*
* @return bool
*/
public static function del($k) {
if ( ! isset(self::$callbacks[$k])) {
return false;
}
unset(self::$callbacks[$k]);
return true;
}
/**
* 执行
*/
public static function run() {
$callbacks = self::$callbacks;
if (empty($callbacks) || empty(self::$checkPass)) {
return false;
}
fastcgi_finish_request();
try {
foreach ($callbacks as $c) {
$c();
}
} catch (\Exception $e) {
//处理异常
}
}
}
使用说明
调用如下:if (FastcigCallbk::check()) {
FastcigCallbk::add(function () use ($list) {
//需要异步处理的程序
});
} else {
//当不支持的时候
}
触发,以thinkphp为例,直接放到项目代码运行结束的时候,如下: