PHP 怎么PHP 调度

wen PHP项目 2

本文目录导读:

PHP 怎么PHP 调度

  1. 定时任务调度
  2. 异步任务调度
  3. 完整示例:多任务调度系统
  4. 选择建议

我来详细讲解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 长连接、实时任务 高性能,支持高并发 需要常驻内存

最佳实践:

  1. 系统级定时任务使用Cron Job
  2. Laravel项目使用内置调度器
  3. 复杂的队列任务使用RabbitMQ/Redis
  4. 实时任务使用Workerman/Swoole

选择哪种方式取决于你的具体需求、项目架构和服务器环境。

抱歉,评论功能暂时关闭!