- 1.提前结束会话(请求), 但是进程仍在执行后续耗时代码 - FastCGI模式下, 使用fastcgi_finish_request()函数能马上结束会话 - 注意: fastcgi_finish_request官方介绍页面下的评论提出需要注意的点[链接](https://www.php.net/manual/zh/function.fastcgi-finish-request.php) 正常脚本结束时php会自动调用session_write_close()函数, 而脚本在处理中的时候占用者session锁,对于后续请求来说是阻塞的.所以要尽快手动调用session_write_close()结束并保存session数据. 这对于其他有竞争锁情况同样适用,没有用了要尽快释放 - 一般模式下(如Apache, Nginx, FastCGI(直接使用fastcgi_finish_request()更方便等), 提前输出内容, 结束会话 <?php //适用于大多数运行模式(不包括命令行模式) set_time_limit(0); //设置不限执行时间 ignore_user_abort(true); //忽略客户端中断 //nginx等可能需要达到4k才会输出buffer,所有先输出一些空字符串 $str = str_repeat(' ', 65536); $str .= '立即输出' . date('Y-m-d H:i:s'); #header('X-Accel-Buffering: no'); // 关闭加速缓冲, 在nginx模式需要开启此行 header("Content-Type: text/html;charset=utf-8"); header("Connection: close");//告诉浏览器不需要保持长连接 header('Content-Length: '. strlen($str));//告诉浏览器本次响应的数据大小只有上面的echo那么多 ob_end_flush(); ob_start(); echo $str; ob_flush(); flush(); //至此,连接已经关闭. 但是进程还不会结束, 以下程序还能运行但不会输出 sleep(10); file_put_contents('./log.txt', '10s后我写入log文本: 时间' . date('Y-m-d H:i:s')); - 注意: 在以下情况中,该方法失效:无论那个模式,gzip一定要关闭; 是window32下web服务不行; [官方说明](https://www.php.net/manual/zh/function.flush.php) 个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。 有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。 - 2.请求子进程的网址, 不等待返回结果(说白了就是发个请求唤起耗时的子脚本, 而不等待这个耗时子脚本返回结果) - fsockopen打开一个网络连接或者一个Unix套接字连接, 忽略返回结果(不等待返回结果) - curl 设置超时时间为1s, 忽略返回结果(不等待返回结果,直接超时,但最短要1s) - 3.开启子进程(确保以下函数没有被禁用) - popen >[官方介绍链接](https://www.php.net/manual/zh/function.popen.php): 打开一个指向进程的管道,该进程由派生给定的command命令执行而产生。他是单向的(只能用于写或读) - 例子1 (不等待子进程返回结果直接结束父脚本) <?php ini_set('date.timezone', 'Asia/shanghai'); echo "父脚本开始\n"; echo date('Y-m-d H:i:s') . "\n"; //&: 转入后台运行; nohup:不挂断地运行命令, 防止当前的终端窗口被关闭后导致进程结束 $cmd = 'nohup php cmd.php &'; pclose(popen($cmd, 'r'));//开启一个子进程后马上关闭, 子进程进入后台处理耗时的处理 echo "父脚本结束"; - 例子2 (等待子进程返回结果在结束父脚本) <?php ini_set('date.timezone', 'Asia/shanghai'); echo "父进程开始\n"; echo date('Y-m-d H:i:s') . "\n"; $cmd1 = 'nohup php cmd.php &'; $cmd2 = 'nohup php cmd1.php &'; //执行耗时异步任务1 $p1 = popen($cmd1, 'r'); //执行耗时异步任务2, 与任务1是并行运行的 $p2 = popen($cmd2, 'r'); register_shutdown_function(function () use ($p1, $p2) { $res1 = stream_get_contents($p1); echo $res1; $res2 = stream_get_contents($p2); echo $res2; pclose($p1); pclose($p2); echo "父脚本结束" . date('Y-m-d H:i:s') . "\n"; }); - proc_open 开启异步子进程 >与popen()一样, 只是该函数有更强的控制程序执行的能力, 可以双向(读又写) >参考例子(https://my.oschina.net/eechen/blog/745504)
- pcntl_fork 需要扩展支持,比较麻烦
- 4.借助框架如swoole等
有其他更好的方式欢迎补充