本文目录导读:

我来详细讲解PHP中的任务调度方法,主要分为定时任务调度和异步任务调度两大类。
定时任务调度
Cron Job(Linux/Unix)
最常用的定时调度方式,在服务器crontab中配置:
# 每分钟执行 * * * * * /usr/bin/php /path/to/your/script.php # 每天凌晨2点执行 0 2 * * * /usr/bin/php /path/to/your/script.php # 每小时执行 0 * * * * /usr/bin/php /path/to/your/script.php
PHP脚本示例(script.php):
<?php
// 记录执行日志
file_put_contents('/tmp/cron.log', date('Y-m-d H:i:s')." 任务执行\n", FILE_APPEND);
// 执行具体业务逻辑
processTasks();
PHP内置的调度器(使用sleep循环)
适用于不需要精确时间的场景:
<?php
while (true) {
// 执行任务
doTask();
// 休眠60秒
sleep(60);
}
使用Laravel任务调度
Laravel提供了优雅的任务调度API:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
// 每分钟执行
$schedule->command('emails:send')->everyMinute();
// 每天午夜执行
$schedule->job(new ProcessPodcast)->daily();
// 自定义调度
$schedule->call(function () {
DB::table('users')->increment('views');
})->hourly();
}
使用workerman/crontab
Workerman框架的定时器组件:
<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
require_once __DIR__ . '/vendor/autoload.php';
$task = new Worker();
$task->onWorkerStart = function($task) {
// 每10秒执行一次
Timer::add(10, function() {
echo "任务执行中...\n";
});
// 每天2:30执行
Timer::add(86400, function() {
echo "每日任务\n";
}, [], true, strtotime('02:30') - time());
};
Worker::runAll();
异步任务调度
使用消息队列(推荐)
Redis队列实现:
<?php
// 生产者:添加任务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$task = [
'type' => 'send_email',
'data' => ['to' => '[email protected]', 'subject' => 'Hello']
];
$redis->rPush('task_queue', json_encode($task));
// 消费者(在另一个进程中运行)
while (true) {
$task = $redis->blPop('task_queue', 0);
if ($task) {
$data = json_decode($task[1], true);
processTask($data);
}
}
使用RabbitMQ:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
// 生产者
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, true, false, false);
$msg = new AMQPMessage('Hello World!');
$channel->basic_publish($msg, '', 'task_queue');
// 消费者
$callback = function($msg) {
echo "收到: ", $msg->body, "\n";
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$channel->basic_consume('task_queue', '', false, false, false, false, $callback);
使用pcntl_fork(进程分叉)
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('无法创建子进程');
} elseif ($pid) {
// 父进程
echo "父进程继续执行\n";
pcntl_wait($status); // 等待子进程结束
} else {
// 子进程执行耗时任务
sleep(10);
echo "子进程任务完成\n";
exit(0);
}
使用GuzzleHttp异步HTTP请求
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client();
// 创建多个异步请求
$promises = [
'user' => $client->getAsync('/api/user'),
'posts' => $client->getAsync('/api/posts'),
'comments' => $client->getAsync('/api/comments')
];
// 等待所有请求完成
$results = Promise\unwrap($promises);
// 处理结果
foreach ($results as $key => $response) {
echo "$key: " . $response->getBody() . "\n";
}
完整示例:多任务调度系统
<?php
class TaskScheduler {
private $tasks = [];
private $running = true;
// 添加定时任务
public function addTask($name, $callback, $interval, $immediate = false) {
$this->tasks[] = [
'name' => $name,
'callback' => $callback,
'interval' => $interval,
'last_run' => $immediate ? 0 : time()
];
}
// 启动调度器
public function run() {
echo "调度器启动...\n";
while ($this->running) {
$current_time = time();
foreach ($this->tasks as &$task) {
if ($current_time - $task['last_run'] >= $task['interval']) {
echo date('H:i:s') . " 执行任务: {$task['name']}\n";
try {
call_user_func($task['callback']);
} catch (Exception $e) {
echo "任务失败: " . $e->getMessage() . "\n";
}
$task['last_run'] = $current_time;
}
}
sleep(1); // 每秒检查一次
}
}
public function stop() {
$this->running = false;
}
}
// 使用示例
$scheduler = new TaskScheduler();
// 添加任务:每5秒执行一次
$scheduler->addTask('task1', function() {
echo "执行task1\n";
}, 5);
// 添加任务:每10秒执行一次
$scheduler->addTask('task2', function() {
echo "执行task2\n";
}, 10);
// 启动调度器(在后台运行)
$pid = pcntl_fork();
if ($pid == 0) {
$scheduler->run();
exit(0);
}
选择建议
| 调度方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Cron Job | 固定时间间隔的任务 | 系统级支持,稳定可靠 | 最小间隔1分钟,不灵活 |
| Laravel调度 | Laravel项目 | 语法优雅,功能丰富 | 依赖Laravel框架 |
| 消息队列 | 异步任务、高并发 | 解耦、可靠、扩展性好 | 需要额外组件支持 |
| pcntl_fork | 简单并行任务 | 原生PHP,无需额外组件 | 进程管理复杂 |
| Workerman | 长连接、实时任务 | 高性能,支持高并发 | 需要常驻内存 |
最佳实践:
- 系统级定时任务使用Cron Job
- Laravel项目使用内置调度器
- 复杂的队列任务使用RabbitMQ/Redis
- 实时任务使用Workerman/Swoole
选择哪种方式取决于你的具体需求、项目架构和服务器环境。