-
博文分类专栏
- Jquery基础教程
-
- 文章:(15)篇
- 阅读:46563
- shell命令
-
- 文章:(42)篇
- 阅读:154236
- Git教程
-
- 文章:(36)篇
- 阅读:234848
- leetCode刷题
-
- 文章:(76)篇
- 阅读:131789
-
PHP函数之fastcgi_finish_request2017-11-27 23:51 阅读(7174) 评论(0)
一、概念
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为例,直接放到项目代码运行结束的时候,如下: