php利用fastcgi_finish_request实现非阻塞及相关拓展

前言

在实际项目中常常会有这样的需求,对于前端发过来的请求,须要在后端进行长时间的处理,但为了让使用者有更好的体验,为了让PHP在后端处理长时间任务时不阻塞,快速响应页面请求,所以在这里对fastcgi_finish_request的应用进行总结概括。固然php实现非阻塞的方式有不少种,好比异步脚本、swoole,但我的认为fastcgi_finish_request最为简单方便。php

基本应用

fastcgi_finish_request介绍

(PHP 5 >= 5.3.3, PHP 7)html

fastcgi_finish_request — 冲刷(flush)全部响应的数据给客户端前端

boolean fastcgi_finish_request ( void )

此函数冲刷(flush)全部响应的数据给客户端并结束请求。 这使得客户端结束链接后,须要大量时间运行的任务可以继续运行。后端

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE服务器

注意问题

  • PHP 与 Web 服务器使用了PHP-FPM(FastCGI进程管理器),那经过fastcgi_finish_request() 函数能立刻结束会话,而 PHP 线程能够继续在后台运行。也就是说只针对php-fpm的进程管理方式才能使用该函数
  • 只要代码运行到这个位置,就已经断开请求返回参数给客户端了。接下来的代码都和客户端没有关系了。也就是说对于输出在页面的内容必须放在fastcgi_finish_request函数以前
  • fastcgi_finish_request()结束客户端链接以后,运行时间依然会受max_execution_time超时时间的影响,也就是说若是预计到代码在后端执行时间比较久,仍是要设定set_time_limit(0)
  • 在高并发下执行时间太久也会致使fastcgi进程不够用,不能及时释放,就会爆502错误了。

应用

echo "program start...";

file_put_contents('/tmp/garylog.log','start-time:'.date('Y-m-d H:i:s')."\n", FILE_APPEND);

fastcgi_finish_request();sleep(1);

// set_time_limit(0);
// sleep(150);

$num = 25;
$num += 1;
sleep(5);
echo 'debug...';
file_put_contents('/tmp/garylog.log', 'start-proceed:'.$num.',时间'.date('Y-m-d H:i:s')."\n", FILE_APPEND);

sleep(10);

file_put_contents('/tmp/garylog.log', 'end-time:'.date('Y-m-d H:i:s')."\n", FILE_APPEND);

运行测试
图片描述swoole

图片描述

兼容非php-fpm

从代码的可移植性讲的话, 能够在代码中附上以下代码:并发

if (!function_exists("fastcgi_finish_request")) {
          function fastcgi_finish_request()  {
          }
    }

不会形成代码部署在非fpm环境下形成问题.异步

保证进程单一运行

对于上面说到的问题:在高并发下执行时间太久也会致使fastcgi进程不够用,不能及时释放。同时咱们的需求仅仅是为了起到触发的做用,并不须要每次运行,那么能够考虑使用下面的方法,避免重复占用进程。函数

$processId = realpath(__FILE__) . '-' . get_class($this);
$filename = md5($processId);
$file = '/tmp/'.$filename;
if(!file_exists($filename)){
    file_put_contents($file, getmypid());
}else{
    return true; 
}


## do somthing 须要长时间处理的代码

//处理完成后删除进程id记录文件
unlink($file);

参考

相关文章
相关标签/搜索