首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 使用 pcntl 與 libevent 實現高精度定時器

     編輯:PHP 相關知識

技術背景

PHP 傳統上缺乏原生的高精度定時器功能。通過結合 pcntl 進程控制擴展與 libevent 事件驅動庫,可以在 CLI 模式下實現毫秒級的定時任務調度,適用於守護進程、任務隊列、實時推送等場景。

核心實現代碼

<?php
/**
 * 創建子進程執行指定函數
 * @param string $func_name 要執行的函數名
 * @param mixed ...$args 傳遞給函數的參數
 * @return int|false 子進程 PID 或失敗返回 false
 */
function newChild($func_name, ...$args) {
    echo "enter newChild\n";
    $pid = pcntl_fork();
    
    if ($pid === 0) {
        // 子進程:執行目標函數並退出
        if (function_exists($func_name)) {
            exit(call_user_func_array($func_name, $args));
        } else {
            exit(-1);
        }
    } elseif ($pid === -1) {
        echo "Couldn't create child process\n";
        return false;
    } else {
        // 父進程:返回子進程 PID
        return $pid;
    }
}

/**
 * 定時器回調函數
 */
function on_timer() {
    echo "timer called\n";
    // 這裡放置定時任務邏輯
}

/**
 * 基於 libevent 的定時器實現
 * @param callable $func 回調函數
 * @param int $timeouts 微秒級延遲
 */
function timer($func, $timeouts) {
    echo "enter timer\n";
    
    // 創建事件基座
    $base = event_base_new();
    if (!$base) {
        throw new Exception("無法創建 event base");
    }
    
    // 創建事件
    $event = event_new();
    if (!$event) {
        throw new Exception("無法創建 event");
    }
    
    // 設置事件屬性:文件描述符 0、超時事件、回調函數
    event_set($event, 0, EV_TIMEOUT, $func);
    
    // 關聯事件基座
    event_base_set($event, $base);
    
    // 添加事件(微秒精度)
    event_add($event, $timeouts);
    
    // 進入事件循環
    event_base_loop($base);
    
    // 清理資源
    event_free($event);
    event_base_free($base);
}

// 使用示例:創建子進程運行 5 秒定時器
$pid = newChild("timer", "on_timer", 5000000); // 5,000,000 微秒 = 5 秒

if ($pid > 0) {
    echo "master process exit\n";
    // 父進程可繼續做其他工作或等待
    pcntl_wait($status); // 等待子進程結束(可選)
}
?>

關鍵技術點解析

1. pcntl_fork 進程分叉

  • 父進程獲得子進程 PID,子進程獲得 0
  • 實現多進程並發,避免定時器阻塞主進程
  • 需在 CLI 模式下運行,Web 環境(FPM/Apache)禁用 pcntl

2. libevent 事件驅動

  • event_base_new():創建事件循環基座
  • event_set():綁定文件描述符、事件類型、回調
  • event_add():註冊事件並設置超時時間(微秒)
  • event_base_loop():進入事件循環,阻塞等待事件觸發

3. 微秒級精度

參數 $timeouts 單位為微秒,5000000 = 5 秒,實現比 sleep() 更精確的定時。

生產環境增強方案

1. 信號處理與優雅退出

<?php
declare(ticks = 1);

$shutdown = false;
pcntl_signal(SIGTERM, function() use (&$shutdown) { $shutdown = true; });
pcntl_signal(SIGINT, function() use (&$shutdown) { $shutdown = true; });

function timer_with_signal($func, $timeouts) {
    global $shutdown;
    $base = event_base_new();
    $event = event_new();
    event_set($event, 0, EV_TIMEOUT | EV_PERSIST, function() use ($func, &$shutdown, $event, $base) {
        if ($shutdown) {
            event_base_loopexit($base);
            return;
        }
        call_user_func($func);
    });
    event_base_set($event, $base);
    event_add($event, $timeouts);
    event_base_loop($base);
}
?>

2. 多任務調度器封裝

<?php
class TimerScheduler {
    private $base;
    private $events = [];
    private $running = false;
    
    public function __construct() {
        $this->base = event_base_new();
    }
    
    public function addTimer(callable $callback, int $intervalMs, bool $persist = true) {
        $event = event_new();
        $flags = $persist ? EV_TIMEOUT | EV_PERSIST : EV_TIMEOUT;
        event_set($event, 0, $flags, $callback);
        event_base_set($event, $this->base);
        event_add($event, $intervalMs * 1000); // 毫秒轉微秒
        $this->events[] = $event;
    }
    
    public function run() {
        $this->running = true;
        event_base_loop($this->base);
    }
    
    public function stop() {
        event_base_loopexit($this->base);
        $this->running = false;
    }
    
    public function __destruct() {
        foreach ($this->events as $event) {
            event_free($event);
        }
        event_base_free($this->base);
    }
}

// 使用示例
$scheduler = new TimerScheduler();
$scheduler->addTimer(function() { echo "每秒任務\n"; }, 1000);
$scheduler->addTimer(function() { echo "每5秒任務\n"; }, 5000);
$scheduler->run();
?>

擴展安裝與環境要求

  • pcntl:PHP 核心擴展,編譯時需 --enable-pcntl,Windows 不支持
  • libevent:需安裝 libevent 庫及 PHP pecl 擴展 pecl install libevent
  • 運行環境:Linux/Unix CLI 模式,不適用於 Web-FPM 架構

替代方案對比

方案精度複雜度適用場景
pcntl + libevent微秒高高性能守護進程、實時系統
Swoole 定時器毫秒低現代 PHP 高性能網絡應用
ReactPHP毫秒中異步非阻塞應用
Crontab + PHP CLI分鐘極低簡單定時腳本、備份清理

總結

pcntl + libevent 組合為 PHP 提供了底層的高精度定時能力,適合構建高性能守護進程。現代項目推薦使用 Swoole 或 ReactPHP 等高級框架,它們封裝了更完善的事件循環與定時器 API,開發效率與維護性更優。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved