PHP多程序程式設計之僵屍程序問題的了解
使用pcntl_fork函數可以讓PHP實作多程序并發或者異步處理的效果:https://www.jb51.net/article/125789.htm
那麼問題是我們産生的程序需要去控制,而不能/【關于環境方面,我覺得DOCKER是非常合适和快速部署的一個方式】/置之不理。最基本的方式就是fork程序和殺死程序。
通過利用pcntl_fork函數,我們已經有了新的子程序,而子程序接下來完成我們需要處理的内容,那麼我們就暫且叫做service()吧,而且我們需要很多個service()進行處理,再次參照我們之前的需求,父程序需要一直循環讀取配置檔案,等待檔案發生改變。通過對pcntl_fork的方式,很容易我們就可以寫出如下代碼:
$res = config();
//kill程序
for($i = 0; $i < $res[sum]; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
service();
return;
}
}
代碼中注釋的地方我們需要在配置檔案中發生改變的時候殺死程序,殺死程序的的方式很簡單,可以使用kill指令直接殺死,比如(假設pid為123):
1 kill 123
但是我們發現,使用這個殺死程序的方式并沒有真正的把程序殺死,這個子程序被殺死後還占用這個程序的資源,我們成為僵屍程序,僵屍程序是使用kill指令無法殺死的。想要解決這個問題,我們能做的隻有兩種方式。
- shutdown
-
殺死該程序的父程序。
但是這兩種方法都不行,因為這個程式的目的是監控常駐在伺服器内,伺服器不能關閉,并且父程序也不能被幹掉。這時候我們看到了官方文檔對于fork方法的解釋:
pcntl_wait($status); //等待子程序中斷,防止子程序成為僵屍程序。
原來有種方式可以防止程序成為僵屍程序,但是,官網給出的代碼是這樣子的:
$pid = pcntl_fork();
//父程序和子程序都會執行下面代碼
if ($pid == -1) {
//錯誤處理:建立/【盡量使用一鍵安裝腳本,要麼自己做,要麼網上下載下傳或使用我部落格的,把時間用在更多的地方,少做重複勞動的事情】/子程序失敗時傳回-1.
die('could not fork');
} else if ($pid) {
//父程序會得到子程序号,是以這裡是父程序執行的邏輯
pcntl_wait($status); //等待子程序中斷,防止子程序成為僵屍程序。
} else {
//子程序得到的$pid為0, 是以這裡是子程序執行的邏輯。
}
什麼意思呢?就是父程序會等待子程序運作,等子程序運作結束之後,才會進行下一步,并且也會消除僵屍程序。但是這裡又和我們的需求不符合了,我們的子程序為一個死循環的程式,不斷的查找輸出,更本沒有結束的時候,并且我們需要的是異步處理而不是同步。但是這個方法可以用嗎?其實當然可以。
在pcntl_wait的文檔中是這麼解釋這個函數的:
wait函數刮起目前程序的執行直到一個子程序退出或接收到一個信号要求中斷目前程序或調用一個信号處理函數。 如果一個子程序在調用此函數時已經退出(俗稱僵屍程序),此函數立刻傳回。子程序使用的所有系統資源将 被釋放。關于wait在您系統上工作的詳細規範請檢視您系統的wait(2)手冊。
我們發現,當這個函數發現子程序成為了僵屍程序就會釋放僵屍程序的資源——前提是這個僵屍程序為這個父程序的子程序。那麼我們就可以巧妙的利用這個方式讓這些僵屍程序釋放資源了,是以就有了如下代碼:
posix_kill(123, 9);
pcntl_wait($status);
這樣我們先使用kill幹掉這個程序,這個程序就不會再運作了,但是這個程序成為了僵屍程序,占用着資源,我們下一句就執行一次pcntl_wait()讓這些僵屍程序釋放資源,這樣,子程序才真正的被終止了,僵屍程序被消除了。