php进程学习(一)
https://www.php.cn/php-ercikaifa-345122.html
https://m.php.cn/article/421935.html
一、在Linux操作系統(tǒng)中有哪些信號
1、簡單介紹信號
信號是事件發(fā)生時對進(jìn)程的通知機制,有時又稱為軟件中斷。一個進(jìn)程可以向另一個進(jìn)程發(fā)送信號,比如子進(jìn)程結(jié)束時都會向父進(jìn)程發(fā)送一個SIGCHLD(17號信號)來通知父進(jìn)程,所以有時信號也被當(dāng)作一種進(jìn)程間通信的機制。
在linux系統(tǒng)下,通常我們使用 kill -9 XXPID來結(jié)束一個進(jìn)程,其實這個命令的實質(zhì)就是向某進(jìn)程發(fā)送SIGKILL(9號信號),對于在前臺進(jìn)程我們通常用Ctrl+c快捷鍵來結(jié)束運行,該快捷鍵的實質(zhì)是向當(dāng)前進(jìn)程發(fā)送SIGINT(2號信號),而進(jìn)程收到該信號的默認(rèn)行為是結(jié)束運行
2、常用信號
下邊這些信號,可以使用kill -l命令進(jìn)行查看
下邊介紹幾個比較重要且常用的信號:
二、PHP中處理信號相關(guān)函數(shù)
PHP的pcntl擴(kuò)展以及posix擴(kuò)展為我們提供了若干操作信號的方法(若想使用這些函數(shù),需要先安裝這幾個擴(kuò)展)
下邊具體介紹幾個我在本次任務(wù)中用到的方法:
declare
declare結(jié)構(gòu)用來設(shè)定一段代碼的執(zhí)行指令。declare的語法和其它流程控制結(jié)構(gòu)相似
declare (directive)
statement
directive部分允許設(shè)定declare代碼段的行為。目前只認(rèn)識兩個指令:ticks和encoding。declare代碼段中的 statement部分將被執(zhí)行——怎樣執(zhí)行以及執(zhí)行中有什么副作用出現(xiàn)取決于directive中設(shè)定的指令
Ticks
Tick(時鐘周期)是一個在declare代碼段中解釋器每執(zhí)行N條可計時的低級語句就會發(fā)生的事件N的值是在declare 中的directive部分用ticks=N來指定的。不是所有語句都可計時。通常條件表達(dá)式和參數(shù)表達(dá)式都不可計時。在每個tick中出現(xiàn)的事件是由register_tick_function() 來指定的,注意每個 tick 中可以出現(xiàn)多個事件 更詳細(xì)的內(nèi)容,可查看官方文檔:https://www.php.net/manual/zh/control-structures.declare.php
輸出:六個“執(zhí)行”
pcntl_signal
pcntl_signal,安裝一個信號處理器
函數(shù)pcntl_signal()為signo指定的信號安裝一個新的信號處理器
declare(ticks = 1); pcntl_signal(SIGINT,function(){echo "你按了Ctrl+C".PHP_EOL; }); while(1){sleep(1);//死循環(huán)運行低級語句 }輸出:當(dāng)按Ctrl+C之后,會輸出“你按了Ctrl+C”
posix_kill
posix_kill,向進(jìn)程發(fā)送一個信號
posix_kill ( int $pid , int $sig ) : bool
第一個參數(shù)為進(jìn)程ID,第二個參數(shù)為你要發(fā)送的信號
a.php
<?php declare(ticks = 1); echo getmypid();//獲取當(dāng)前進(jìn)程id pcntl_signal(SIGINT,function(){echo "你給我發(fā)了SIGINT信號"; }); while(1){sleep(1); }b.php
<?php posix_kill(執(zhí)行1.php時輸出的進(jìn)程id, SIGINT); pcntl_signal_dispatch pcntl_signal_dispatch,調(diào)用等待信號的處理器pcntl_signal_dispatch ( void ) : bool
函數(shù)pcntl_signal_dispatch()調(diào)用每個等待信號通過pcntl_signal()安裝的處理器
輸出:
安裝信號處理器…
為自己生成SIGHUP信號…
分發(fā)…
信號處理器被調(diào)用
完成
pcntl_async_signals()
異步信號處理,用于啟用無需 ticks (這會帶來很多額外的開銷)的異步信號處理。(PHP>=7.1)
<?php pcntl_async_signals(true); // turn on async signalspcntl_signal(SIGHUP, function($sig) {echo "SIGHUP\n"; });posix_kill(posix_getpid(), SIGHUP);輸出:
SIGHUP
三、PHP中處理信號量的方式
前邊我們知道我們可以通過declare(ticks=1) 和 pcntl_signal組合的方式監(jiān)聽信號,即每一條PHP低級語句,就會檢查一次當(dāng)前進(jìn)程是否有未處理的信號,這其實是十分耗性能的。
pcntl_signal的實現(xiàn)原理是,觸發(fā)信號后先將信號加入一個隊列中。然后在PHP的ticks回調(diào)函數(shù)中不斷檢查是否有信號,如果有信號就執(zhí)行PHP中指定的回調(diào)函數(shù),如果沒有則跳出函數(shù)。
PHP_MINIT_FUNCTION(pcntl) {php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);php_add_tick_function(pcntl_signal_dispatch TSRMLS_CC);return SUCCESS; }在PHP5.3之后,有了 pcntl_signal_dispatch 函數(shù)。這個時候?qū)⒉辉谛枰猟eclare,只需要在循環(huán)中增加該函數(shù),就可以調(diào)用信號通過了:
<?php echo getmypid();//獲取當(dāng)前進(jìn)程id pcntl_signal(SIGUSR1,function(){echo "觸發(fā)信號用戶自定義信號1"; }); while(1){pcntl_signal_dispatch();sleep(1);//死循環(huán)運行低級語句 }大家都知道PHP的ticks=1表示每執(zhí)行1行PHP代碼就回調(diào)此函數(shù)。實際上大部分時間都沒有信號產(chǎn)生,但ticks的函數(shù)一直會執(zhí)行。如果一個服務(wù)器程序1秒中接收1000次請求,平均每個請求要執(zhí)行1000行PHP代碼。那么PHP的pcntl_signal,就帶來了額外的 1000 * 1000,也就是100萬次空的函數(shù)調(diào)用。這樣會浪費大量的CPU資源。比較好的做法是去掉ticks,轉(zhuǎn)而使用pcntl_signal_dispatch,在代碼循環(huán)中自行處理信號。 pcntl_signal_dispatch 函數(shù)的實現(xiàn):
void pcntl_signal_dispatch() {//.... 這里略去一部分代碼,queue即是信號隊列while (queue) {if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {ZVAL_NULL(&retval);ZVAL_LONG(¶m, queue->signo);/* Call php signal handler - Note that we do not report errors, and we ignore the return value *//* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */call_user_function(EG(function_table), NULL, handle, &retval, 1, ¶m TSRMLS_CC);zval_ptr_dtor(¶m);zval_ptr_dtor(&retval);}next = queue->next;queue->next = PCNTL_G(spares);PCNTL_G(spares) = queue;queue = next;} }但是上邊這種,也有個惡心的地方就是,它得放在死循環(huán)中。PHP7.1之后出來了一個完成異步的信號接收并處理的函數(shù): pcntl_async_signals
<?php //a.php echo getmypid(); pcntl_async_signals(true);//開啟異步監(jiān)聽信號 pcntl_signal(SIGUSR1,function(){echo "觸發(fā)信號";posix_kill(getmypid(),SIGSTOP); }); posix_kill(getmypid(),SIGSTOP);//給進(jìn)程發(fā)送暫停信號//b.php posix_kill(文件1進(jìn)程, SIGCONT);//給進(jìn)程發(fā)送繼續(xù)信號 posix_kill(文件1進(jìn)程, SIGUSR1);//給進(jìn)程發(fā)送user1信號 通過pcntl_async_signals方法,就不用再寫死循環(huán)了。監(jiān)聽信號的包:
composer require rain-life/monitor-signal
總結(jié)
以上是生活随笔為你收集整理的php进程学习(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在laravel5 中使用queue队列
- 下一篇: 宝塔使用webhook自动部署php项目