• 你好!欢迎你的到来
  • 关于我们
  • 首页 博客 学习笔记 技术导航 工具
  • 博文分类
    • PHP(43)
    • MySQL(11)
    • Linux(28)
    • html(3)
    • JQuery(4)
    • JavaScript(9)
    • svn(2)
    • CSS(2)
    • seajs(1)
    • go(44)
    • redis(1)
    • nginx(8)
    • mongo(0)
    • java(0)
    • 算法(0)
    • 其他(26)
    • 生活(1)
    专栏
    • Jquery基础教程
      • 文章:(15)篇
      • 阅读:33316
    • shell命令
      • 文章:(42)篇
      • 阅读:108621
    • Git教程
      • 文章:(36)篇
      • 阅读:179638
    • leetCode刷题
      • 文章:(76)篇
      • 阅读:64012
    • 摘要视图
    • 目录视图
    PHP函数之fastcgi_finish_request
    标签: 函数fastcgi_finish_request
    2017-11-27 23:51 阅读(5396) 评论(0)

    一、概念

    fastcgi_finish_request函数主要是用来,将已经处理的数据返回给客户端,并结束请求,同时在后台继续处理fastcgi_finish_request函数后面的任务。格式如下:

    boolean fastcgi_finish_request ( void )

    返回值

    成功时返回 TRUE, 或者在失败时返回 FALSE。

    需要注意以下几点

    1. 在运行完函数fastcgi_finish_request后,虽然结束了客户端的请求,但是仍然需要占用php-fpm进程处理后续任务,如果任务特别耗时,这样就会带来一个问题,php-fpm进程都被占用,当请求再次到来的时候,就会出现网关错误。

    2. 当以命令行的模式,是没法调用fastcgi_finish_request函数的。

    3. 在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为例,直接放到项目代码运行结束的时候,如下:

    本文为原创文章,请尊重辛勤劳动,如需转载,请保留本文地址
    http://www.findme.wang/blog/detail/id/283.html

    若您感觉本站文章不错,读后有收获,不妨赞助一下?

    我要赞助

    您还可以分享给朋友哦

    更多
    顶
    3
    踩
    0
    • 上一篇: PHP函数之get_defined_vars
    • 下一篇: 修改Linux的shell从默认的bash切换为zsh
    • 查看评论
    • 正在加载中...
    • 留言
    • 亲,您还没有登录,登录后留言不需要审核哦!
      可以使用如下方式登录哦!
  • CSDN | 新浪微博 | github | 关于我们 | 我要留言 | 友链申请
  • 豫ICP备18038193号    Copyright ©lidequan All Rights Reserved