如何实现PHP页面加载与24小时长时脚本并行运行?
嘿,我太懂你这种被长循环卡死页面的憋屈了——24小时的任务直接把页面锁死,用户体验拉满(负的)。给你三个亲测有效的方案,直接上手就行:
方案1:PHP内置函数实现「页面先出,后台续跑」
这个方案不用额外依赖,靠PHP自身的输出缓冲和断开连接机制,让页面先返回内容,脚本在后台偷偷执行循环。
<?php // 开启输出缓冲,用来攒住页面内容 ob_start(); // 告诉浏览器:我内容发完了,别等了 header('Connection: close'); header('Content-Length: ' . ob_get_length()); // 输出你正常要显示的页面内容 echo "页面加载完成!后台任务正在默默执行..."; // 强制把内容推给浏览器,断开和用户的连接 ob_end_flush(); flush(); // 关键:允许脚本在用户断开连接后继续跑 ignore_user_abort(true); // 开始你的长时循环 $getEnergy = 0; $maxEnergy = 1200; $step = 0.14; while ($getEnergy < $maxEnergy) { // 这里写你的循环业务逻辑,比如更新数据、写入日志等 $getEnergy += $step; // 取消脚本超时限制(避免中途被PHP杀掉) set_time_limit(0); // 可选:每次循环休眠0.1秒,别把CPU跑满 usleep(100000); } ?>
注意点:
- 有些主机商可能会限制
ignore_user_abort或set_time_limit,需要确认服务器配置; - 如果循环里有IO操作(比如写数据库),记得加异常处理,避免脚本中途崩溃。
方案2:把任务丢进系统后台执行(更稳定)
把循环单独拆成一个脚本,主页面通过系统命令让它在后台跑,页面直接返回,完全不卡。
第一步:写独立的任务脚本(比如energy_task.php)
<?php $getEnergy = 0; $maxEnergy = 1200; $step = 0.14; // 取消超时限制+允许后台执行 set_time_limit(0); ignore_user_abort(true); while ($getEnergy < $maxEnergy) { // 你的循环逻辑 $getEnergy += $step; usleep(100000); } ?>
第二步:主页面调用它
<?php // 输出正常页面内容 echo "任务已提交到后台,放心刷页面吧!"; // 用exec把脚本丢进系统后台,nohup确保进程不会随主页面结束而死掉 // > /dev/null 2>&1 是把日志丢去黑洞,避免生成大文件占磁盘 exec("nohup php " . __DIR__ . "/energy_task.php > /dev/null 2>&1 &"); ?>
注意点:
- 服务器要允许PHP调用
exec函数(有些安全配置会禁用); - 要确保PHP有执行该脚本的权限,路径别写错。
方案3:消息队列(生产环境首选,最靠谱)
如果是正式项目,前面两种方案有风险(比如服务器重启任务就没了),用消息队列+常驻进程的方式,稳定到离谱。这里以Redis为例:
第一步:主页面把任务丢进队列
<?php // 连接Redis(需要先安装Redis扩展) $redis = new Redis(); $redis->connect('127.0.0.1', 6379); // 把任务参数序列化后丢进队列 $taskData = [ 'getEnergy' => 0, 'maxEnergy' => 1200, 'step' => 0.14 ]; $redis->lPush('energy_tasks', json_encode($taskData)); // 输出页面内容 echo "任务已加入处理队列,后台马上开始干活!"; ?>
第二步:写常驻消费脚本(energy_consumer.php)
<?php set_time_limit(0); ignore_user_abort(true); $redis = new Redis(); $redis->connect('127.0.0.1', 6379); // 一直监听队列,有任务就处理 while (true) { // 阻塞式取任务,没任务就等着,不占CPU $taskJson = $redis->brPop('energy_tasks', 0); if ($taskJson) { $taskData = json_decode($taskJson[1], true); $getEnergy = $taskData['getEnergy']; $maxEnergy = $taskData['maxEnergy']; $step = $taskData['step']; while ($getEnergy < $maxEnergy) { // 你的循环逻辑 $getEnergy += $step; usleep(100000); } } // 处理完一个任务后歇1秒,给Redis喘口气 sleep(1); } ?>
第三步:用进程管理工具让消费者常驻
用supervisor或者systemd把energy_consumer.php做成系统服务,这样服务器重启后会自动启动,任务永远不会丢。
内容的提问来源于stack exchange,提问作者Draecal
相关产品推荐
相关产品推荐

