PHP 中實作Timer功能,中間使用到了php多線程,本文給出來pcntl的解釋。
PHP 使用pcntl和libevent 實作Timer功能,先看例子,pcntl(PHP執行緒)解釋在下面。
<?php function newChild($func_name) { echo "enter newChild\n"; $args = func_get_args(); unset($args[0]); $pid = pcntl_fork(); if ($pid == 0) { function_exists($func_name) and exit(call_user_func_array($func_name, $args)) or exit(-1); } else if($pid == -1) { echo "Couldn't create child process"; } else { return $pid; } } (PS:^_^不错的php开发交流群:256271784,验证:csl,有兴趣的话可以加入进来一起讨论) function on_timer() { echo "timer called\n"; } /** * @param $func string, function name * @param $timeouts int, microtimes for time delay */ function timer($func, $timeouts){ echo "enter timer\n"; $base = event_base_new(); $event = event_new(); event_set($event, 0, EV_TIMEOUT, $func); event_base_set($event, $base); event_add($event, $timeouts); event_base_loop($base); } $pid = newChild("timer", "on_timer", 5000000); if ($pid > 0) { echo "master process exit\n"; }
PHP 擴展pcntl 實現” 多線程”( 進程)
pcntl 與ticks
ticks 是透過declare(ticks = n) {statement} 語法定義的, declare 語法目前只能接受ticks, 他定義的ticks = n 的意義是當declare 指定的語句區塊中執行了N 條低階語句去發生一個事件, 這個事件可以透過register_tick_function($function_name) 來註冊.
pcntl 的訊號機制是基於ticks 機制實現的. 因此, 我們使用pcntl 族函數中信號相關的函數時, 需要在前面增加declare(ticks = n) 語法結構.
int pcntl_alarm(int $seconds):
$seconds 秒後向進程發送一個SIGALRM 訊號, 每次呼叫pcntl_alarm 方法都會取消先前設定的時脈.
void pcntl_exec(string $path[, array $args[, array $env]]):
在目前行程空間執行程式.
$path: 必須是二進位執行檔, 或具有有效腳本頭資訊(#!/usr/local/bin/php) 的腳本檔路徑.
$args: 將要傳遞給該程式的字串參數列表( 數組形式)
$envs: 環境變數. 以數組(key => value 形式) 方式傳遞給要執行程式的環境變數.
int pcntl_for k (void):
建立一個子進程, 該子進程與父進程只是PID( 進程號) 和PPID( 父進程號) 不同.
在父線程執行時返回創建的子進程pid, 在子線程執行時返回0, 創建子進程失敗時會在父進程上下文返回-1, 並引發php 錯誤.
理解這裡的fork 需要知道: pcntl_fork 創建的是一個分支節點, 相當於一個標記, 父進程完成後, 子進程會從標記處繼續執行, 也就是說pcntl_fork 後面的程式碼分別被父進程和子進程執行了兩遍, 而兩個進程在執行過程中得到的返回值是不同的. 因此, 才可以分離父子進程執行不同的代碼.
int pcntl_getpriority([int $pid = getmypid()[, int $process_identifier = PRIO_PROCESS]]):
取得給定$pid 對應的程序的優先權, 預設是透過getmypid() 取得到的值也就是目前進程.
$pid: 如果沒有指定, 預設是當前進程.
$process_identifier: PRIO_PGRP, PRIO_USER, PRIO_PROCESS 三者之一, 預設PRIO_PROCESS. 其中PRIO_PGRP 指取得進程組的優先權, PRIO_USER 指標取得使用者行程的優先權, PRIO_PROCESS 指取得特定行程優先權.
傳回行程的優先權, 或在發生錯誤時傳回false, 值越小說明越優先
bool pcntl_setpriority(int $priority[, int $pid = getmypid()[, int $process_identifier = PRIO_PROCESS]]:
設定行程的優先權.
$priority: 優先權值, -20 到20 的範圍內, 預設優先權為0. 值為越小說明越優先.
$pid: 如果沒有指定, 指當前程序
$process_identifier: 意義同pcntl_getpriority 的$process_identifier.
設定成功回傳TRUE, 失敗回傳FALSE.
bool pcntl_signal_dispatch(signal_dispatch( void):
呼叫透過pcntl_signal() 安裝的即將發生的訊號的處理器.
呼叫成功返回TRUE,失敗回傳false.
php 5.3.3 加入
bool pcntl_signal(int $signo , callback $handler[, bool $restart_syscalls = true]):
為指定的訊號$signo 安裝一個新的訊號處理器$handler.
最後一個參數不明白意義.
bool pcntl_sigprocmask(int $how, array $set[, array &$oldset]):
增加, 刪除或設定鎖定訊號, 特定的行為依賴於$how 參數
$how: SIG_BLOCK 用於將訊號增加到目前鎖定訊號中, SIG_UNBLOCK 用於把訊號從目前鎖定訊號移除, SIG_SETMASK 用於用給定的訊號清單取代目前鎖定訊號.
$set: 要增加, 移除或設定的訊號清單.
$ oldset: 用於向呼叫者傳回舊的鎖定訊號.
成功傳回TRUE, 失敗回傳FALSE.
int pcntl_sigtimedwait(array $set[, array &$siginfo[, int $seconds = 0[, int $ nanoseconds = 0]]]):
pcntl_sigtimedwait 實際上和pcntl_sigwaitinfo() 所做的是同樣的事情, 不過pcntl_sigtimedwait 多了兩個增強的參數$seconds 和$nanoseconds, 這樣就允許腳本的停留時間有一個上限而不是無限制等待.
$set: 需要等待的信號列表
$siginfo: 用來向調用者返回等待得到的信號的信息, 信息內容見pcntl_sigwaitinfo
#$seconds: 超時的秒數
$nanoseconds: 超時的奈秒數
成功後, pcntl_sigtimedwiat() 傳回訊號編號
int pcntl_sigwaitinfo(array $set[, array &$siginfo]):
掛起目前腳本的執行, 直到接受到$set 中的某個訊號, 如果其中的一個訊號將要到達( 例如被pcntl_sigprocmask 鎖定) 那麼用來向呼叫者回傳等待得到的訊號的資訊, 此資訊包含以下內容:
1. 所有訊號所包含以下三個資訊:##a) signo: 訊號編號
b) signo: 訊號編號##b) signo: 訊號編號# : ##c) code: 訊號代碼
2. SIGCHLD 訊號特有的資訊
a) 記憶 stime: 系統消耗時間
d) pid: 發送進程id
e) uid: 傳送程序的真實使用者id
3. SIGILL #4. SIGPOLL 獨特的資訊:
a) band: band event, 意義未知
#b) fd:2102_$D
b) fd:2102_$poffffpfpffpfpfpfpfpfpfpfp
#########################################
以上是如何使用PHP中pcntl和libevent實現Timer功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!