PHP 实现进程锁与多进程控制:防止定时任务重叠运行

一只小鹿
一只小鹿
发布时间:2026-10-13| 10人浏览过
原创

在使用 Linux 定时任务(Crontab)运行 PHP 脚本时,若程序处理耗时超过调度间隔,容易引发同一任务的多个实例同时运行,造成资源浪费甚至数据错误。通过引入进程锁机制,可以有效控制并发的脚本实例数量。

为什么需要进程锁

进程锁的核心目的是防止重复执行。当定时任务每分钟触发一次,而上次执行的进程尚未结束时,新的进程会立即生成。加上锁判断后,新进程会检测锁文件是否存在,若存在则放弃执行,从而保证只有一个实例在运行。

准备条件

  1. Linux 环境:推荐使用 Shell 命令和后台运行。
  2. 文件写入权限:确保运行 PHP 的用户对指定目录有写权限,以便创建锁文件。
  3. PHP 基础扩展:主要依赖 flock 函数,这是标准库函数,无需额外安装。

第1步:实现单进程的固定锁

最简单的方式是为整个脚本创建一个固定的锁文件。每次执行时尝试获取独占锁,获取失败说明已有进程在运行。

新建 process.php,代码如下:

<?php
$lock_file = dirname(__FILE__) . "/process.lock";
$lock_file_handle = fopen($lock_file, 'w');
if ($lock_file_handle === false) {
    die("Can not create lock file {$lock_file}\n");
}

// LOCK_EX + LOCK_NB:以独占方式加锁,且不阻塞(无法获取立刻报错)
if (!flock($lock_file_handle, LOCK_EX + LOCK_NB)) {
    die(date("Y-m-d H:i:s") . " Process already exists.\n");
}

while(1){
    sleep(1); // 模拟长时间运行,测试时请按需调整
}

在命令行使用 & 符号在后台启动该脚本:

php process.php &

第一次执行会正常运行,若在另一个终端再次运行同一脚本,则会输出:Process already exists.,表示被锁拒止。这种实现适合只有一个固定入口的脚本。

第2步:进程锁实现多进程

实际场景中,可能需要允许不同业务逻辑(如不同的用户ID或任务类型)并行执行。可以通过脚本参数(Argv)来生成不同的锁文件名,实现“一类一锁”的效果。

改进后的代码如下:

if(!($argc > 1)){
    // 无参数:默认使用全局锁
    $lock_file = dirname(__FILE__) . "/process.lock";
}else{
    // 有参数:根据参数组合生成锁名
    unset($argv[0]); // 移除脚本自身名称
    $lock_file = dirname(__FILE__) . "/process". implode('.', $argv) .".lock";
}

$lock_file_handle = fopen($lock_file, 'w');
if ($lock_file_handle === false){
    die("Can not create lock file $lock_file\n");
}

if (!flock($lock_file_handle, LOCK_EX + LOCK_NB)) {
    die(date("Y-m-d H:i:s") . " Process already exists.\n");
}

while(1){
    sleep(1);
}

效果验证:

  • 执行 php process.php 1 成功后,再执行 php process.php 1 会被拦截。
  • 此时执行 php process.php 2 将成功运行,因为锁文件变为 process.2.lock,互不影响。
  • 传入多参数如 php process.php 1 2 也会生成特定的 process.1.2.lock 进行隔离。

第3步:在框架(如 Yii2)中的集成

在实际项目中,通常使用框架(如 Yii2)。框架的控制器的参数传递更加规范,原理相同。

核心步骤:

  1. 继承 Controller:确保你的类继承自 yii\console\Controller,以便正确处理控制台参数。
  2. 添加逻辑:在 action 方法的头部嵌入上述的第2步代码。
  3. Crontab 调用:通过控制台命令格式调用。例如:
* * * * * root /usr/local/bin/php /data/www/html/newVanish/yii 控制器名/方法 传递的参数 > /dev/null 2>&1

这样既利用了框架的便利性,又获得了底层的并发保护。

第4步:强制清理僵死进程(风险提醒)

如果在测试过程中卡死,或者由于非正常退出导致锁文件残留但进程已消失,可以手动终止对应的 PHP 进程。

以下命令可根据进程特征批量杀除,请谨慎操作:

ps aux|grep process_name |grep -v grep|awk '{print $2}'|xargs kill -9

注意:请将 process_name 替换为实际的进程标识字符串。该命令直接终止进程号,可能导致数据未保存,使用前建议确认进程状态。

完成判断与总结

通过检查 die() 的输出或进程列表(ps),即可确认锁是否生效。以上就是 PHP 中实现进程锁与多进程控制的详细内容,更多关于 PHP 优化与并发处理的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。