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); // 等待子進程結束(可選)
}
?>
event_base_new():創建事件循環基座event_set():綁定文件描述符、事件類型、回調event_add():註冊事件並設置超時時間(微秒)event_base_loop():進入事件循環,阻塞等待事件觸發參數 $timeouts 單位為微秒,5000000 = 5 秒,實現比 sleep() 更精確的定時。
<?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);
}
?>
<?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();
?>
--enable-pcntl,Windows 不支持pecl install libevent| 方案 | 精度 | 複雜度 | 適用場景 |
|---|---|---|---|
| pcntl + libevent | 微秒 | 高 | 高性能守護進程、實時系統 |
| Swoole 定時器 | 毫秒 | 低 | 現代 PHP 高性能網絡應用 |
| ReactPHP | 毫秒 | 中 | 異步非阻塞應用 |
| Crontab + PHP CLI | 分鐘 | 極低 | 簡單定時腳本、備份清理 |
pcntl + libevent 組合為 PHP 提供了底層的高精度定時能力,適合構建高性能守護進程。現代項目推薦使用 Swoole 或 ReactPHP 等高級框架,它們封裝了更完善的事件循環與定時器 API,開發效率與維護性更優。