PHP 怎么长期运行流程

wen PHP项目 1

本文目录导读:

PHP 怎么长期运行流程

  1. 命令行脚本(CLI)模式
  2. 使用 Supervisor 管理进程
  3. 使用 ReactPHP 异步框架
  4. 使用 Swoole 高性能框架
  5. 使用 Amp 异步并发框架
  6. 使用 Workerman
  7. 使用消息队列
  8. 进程守护脚本
  9. 最佳实践建议
  10. 注意事项

在 PHP 中实现长期运行(Long-running)的进程或流程,主要有以下几种方案,每种都有不同的适用场景:

命令行脚本(CLI)模式

最基本的方式,使用 PHP CLI 运行脚本。

<?php
// long_running.php
set_time_limit(0); // 取消时间限制
ini_set('memory_limit', '512M');
while (true) {
    // 处理任务
    echo "Processing... " . date('Y-m-d H:i:s') . "\n";
    sleep(5); // 等待5秒
    // 检查退出条件
    if (shouldExit()) {
        break;
    }
}
// 运行: php long_running.php

使用 Supervisor 管理进程

推荐的生产环境方案,使用 Supervisor 来监控和管理 PHP 进程。

# /etc/supervisor/conf.d/php-worker.conf
[program:php-worker]
command=php /path/to/worker.php
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/php-worker.err.log
stdout_logfile=/var/log/php-worker.out.log

使用 ReactPHP 异步框架

<?php
// 使用 Composer 安装: composer require react/event-loop
require 'vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
// 定时任务
$loop->addPeriodicTimer(2, function () {
    echo "每秒执行的任务\n";
});
// 处理流
$stream = fopen('php://stdin', 'r');
$loop->addReadStream($stream, function ($stream) use ($loop) {
    $data = fread($stream, 1024);
    if ($data) {
        echo "收到输入: " . trim($data) . "\n";
    }
});
$loop->run();

使用 Swoole 高性能框架

<?php
// 安装: pecl install swoole
// HTTP 服务器
$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->on("start", function ($server) {
    echo "Swoole HTTP server is started at http://127.0.0.1:9501\n";
});
$http->on("request", function ($request, $response) {
    $response->header("Content-Type", "text/plain");
    $response->end("Hello Swoole\n");
});
// 定时器
$http->tick(1000, function () {
    echo "每1秒执行\n";
});
$http->start();
// 运行: php server.php

使用 Amp 异步并发框架

<?php
// composer require amphp/amp
require 'vendor/autoload.php';
use Amp\Loop;
function processQueue() {
    return new Amp\Coroutine(function () {
        while (true) {
            yield new Amp\Delayed(1000); // 延迟1秒
            echo "处理队列任务...\n";
        }
    });
}
Loop::run(function () {
    yield processQueue();
});

使用 Workerman

<?php
// composer require workerman/workerman
require 'vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:2345');
$worker->onConnect = function ($connection) {
    echo "新连接\n";
};
$worker->onMessage = function ($connection, $data) {
    $connection->send('Hello ' . $data);
};
// 定时器
Worker::getEventLoop()->add(5, function () {
    echo "每5秒执行\n";
});
Worker::runAll();

使用消息队列

结合 Redis、RabbitMQ 等消息队列组件。

<?php
// 使用 Redis 队列
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
while (true) {
    // 阻塞获取队列任务
    $task = $redis->brpop('task_queue', 5);
    if ($task) {
        echo "处理任务: " . $task[1] . "\n";
        // 执行任务处理逻辑
        processTask($task[1]);
    } else {
        // 队列为空,等待
        usleep(100000);
    }
}

进程守护脚本

一个完整的守护进程示例:

<?php
class DaemonProcess {
    private $pid;
    private $isRunning = false;
    public function start() {
        if ($this->isRunning) {
            throw new Exception("进程已经在运行");
        }
        // 防止僵尸进程
        pcntl_signal(SIGCHLD, SIG_IGN);
        pcntl_signal(SIGTERM, [$this, 'handleSignal']);
        pcntl_signal(SIGHUP, [$this, 'handleSignal']);
        $this->isRunning = true;
        $this->run();
    }
    private function run() {
        while ($this->isRunning) {
            // 在这里执行你的业务逻辑
            $this->processTasks();
            // 处理信号
            pcntl_signal_dispatch();
            sleep(5);
        }
    }
    private function processTasks() {
        echo "处理任务: " . date('Y-m-d H:i:s') . "\n";
        // 具体任务逻辑
    }
    public function handleSignal($signo) {
        switch ($signo) {
            case SIGTERM:
                echo "收到终止信号\n";
                $this->isRunning = false;
                break;
            case SIGHUP:
                echo "收到挂起信号,重新加载配置\n";
                // 重新加载配置
                break;
        }
    }
    public function stop() {
        $this->isRunning = false;
    }
}
// 使用
$daemon = new DaemonProcess();
$daemon->start();

最佳实践建议

  1. 使用 Supervisor 管理所有长期运行的 PHP 进程
  2. 做好错误处理 和日志记录
  3. 使用 register_shutdown_function 处理意外退出
  4. 定期重启 避免内存泄漏
  5. 设置合理的内存限制
  6. 使用消息队列 解耦任务

注意事项

  • 避免在循环中创建大量对象导致内存泄漏
  • 使用 gc_collect_cycles() 手动触发垃圾回收
  • 定期检查进程状态
  • 对于 CPU 密集型任务,考虑使用 PHP 扩展(如 Swoole)

根据你的具体需求(是否处理 HTTP 请求、是否需要并发、性能要求等),选择合适的方案,如果只是简单的后台服务,CLI + Supervisor 就足够了。

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