《PHP實戰(zhàn):PHP多進(jìn)程編程實例》要點:
本文介紹了PHP實戰(zhàn):PHP多進(jìn)程編程實例,希望對您有用。如果有疑問,可以聯(lián)系我們。
羨慕火影忍者里鳴人的影分身么?沒錯,PHP程序是可以開動影分身的!想完成任務(wù),又覺得一個進(jìn)程太慢,那么,嘗嘗用多進(jìn)程來搞吧.這篇文章將會介紹一下PHP多進(jìn)程的基本需求,如何創(chuàng)建多進(jìn)程以及基本的信號控制,暫時不會告訴你如何進(jìn)行進(jìn)程間通信和信息共享.PHP學(xué)習(xí)
1. 準(zhǔn)備PHP學(xué)習(xí)
在動手之前,請確定你用的不是M$ Windows平臺(因為我沒有Windows).Linux / BSD / Unix應(yīng)該都是沒問題的.確認(rèn)好了工作環(huán)境以后一起來看看我們必要的PHP模塊是否都有.打開終端輸入下面的命令:PHP學(xué)習(xí)
這個命令檢查并打印當(dāng)前PHP所有開啟的擴展,看一下pcntl和posix是否在輸出的列表中.PHP學(xué)習(xí)
1.1. pcntlPHP學(xué)習(xí)
如果找不到pcntl,八成是編譯的時候沒把這個擴展編譯進(jìn)去.如果你和我一樣是編譯安裝的PHP,那么必要重新編譯安裝PHP.在配置的時候記得加上--enable-pcntl參數(shù)即可.PHP學(xué)習(xí)
1.2. posixPHP學(xué)習(xí)
這貨一般默認(rèn)就會裝上,只要你編譯的時候沒有加上--disable-posix.PHP學(xué)習(xí)
2. 預(yù)備知識PHP學(xué)習(xí)
在繼續(xù)之前,你還需要對Linux多進(jìn)程有一點了解.多進(jìn)程是咋回事呢?這里可跟火影忍者里的影分身稍微有點不同.首先,鳴人從小長到大,好比16歲,咳.有一天他發(fā)動了影分身,分出了5個他.顯然,這些分身也是16歲的鳴人而不是剛出生啥也不懂就會哭的嬰兒(那叫克隆).然后,不一樣的地方來了:分身們變成了獨立的人各自去做各自的事,互相之間不再知道其他分身和原身都做了什么(當(dāng)然不會像動畫片里一樣積累經(jīng)驗給原身啦).除非,他們互相之間有交流,不然,只有16歲之前的事情才是他們共同的記憶.PHP學(xué)習(xí)
有同學(xué)說了,老大你這不坑爹呢么?我又沒看過火影忍者!那你去看一遍好了……PHP學(xué)習(xí)
最后,預(yù)備知識完了,便是大致了解一下主進(jìn)程開出來的子進(jìn)程是怎么回事.子進(jìn)程的代碼和主進(jìn)程是完全一樣的,還有一部分一樣的東西便是直到發(fā)動影分身之前執(zhí)行的所有內(nèi)容.PHP學(xué)習(xí)
3. 影分身之術(shù)PHP學(xué)習(xí)
所以呢,沒有點基礎(chǔ)知識怎么能理解卷軸里的內(nèi)容呢?打開卷軸首先看到了一個單詞:fork.PHP學(xué)習(xí)
3.1. forkPHP學(xué)習(xí)
叉子?叉子是分岔的,一個變多個嘛!差不多就是這個意思.創(chuàng)建子進(jìn)程就用這個命令.這里必要用到pcntl_fork()函數(shù).(可以先簡單看一下PHP手冊關(guān)于這個函數(shù)的介紹.)創(chuàng)建一個PHP腳本:
PHP學(xué)習(xí)
3.2. 分配任務(wù)PHP學(xué)習(xí)
然后我們來說說鳴人16歲那次影分身的事兒,給原身和分身分配兩個簡單的輸出任務(wù):
PHP學(xué)習(xí)
3.3. 子進(jìn)程回收PHP學(xué)習(xí)
剛剛有man ps么?一般我習(xí)慣用ps aux加上grep命令來查找運行著的后臺進(jìn)程.其中有一列STAT,標(biāo)識了每個進(jìn)程的運行狀態(tài).這里,我們關(guān)注狀態(tài)Z:僵尸(Zombie).當(dāng)子進(jìn)程比父進(jìn)程先退出,而父進(jìn)程沒對其做任何處理的時候,子進(jìn)程將會釀成僵尸進(jìn)程.Oops,又跟火影里的影分身不一樣了.鳴人的影分身被干死了以后就自動消失了,但是這里的子進(jìn)程分身死了話還留著一個空殼在,直到父進(jìn)程回收它.僵尸進(jìn)程雖然不占什么內(nèi)存,但是很礙眼,院子里一堆躺著的僵尸怎么都覺得怪怪的.(別忘了它們還占用著PID)PHP學(xué)習(xí)
一般來說,在父進(jìn)程結(jié)束之前回收掛掉的子進(jìn)程就可以了.在pcntl擴展里面有一個pcntl_wait()函數(shù),它會將父進(jìn)程掛起,直到有一個子進(jìn)程退出為止.如果有一個子進(jìn)程釀成了僵尸的話,它會立即返回.所有的子進(jìn)程都要回收,所以多等等也沒關(guān)系啦!PHP學(xué)習(xí)
3.4. 父進(jìn)程先掛了PHP學(xué)習(xí)
如果父進(jìn)程先掛了怎么辦?會發(fā)生什么?什么也不會發(fā)生,子進(jìn)程依舊還在運行.但是這個時候,子進(jìn)程會被交給1號進(jìn)程,1號進(jìn)程成為了這些子進(jìn)程的繼父.1號進(jìn)程會很好地處理這些進(jìn)程的資源,當(dāng)它們結(jié)束時1號進(jìn)程會自動回收資源.所以,另一種處理僵尸進(jìn)程的臨時方法是關(guān)閉它們的父進(jìn)程.PHP學(xué)習(xí)
4. 信號PHP學(xué)習(xí)
一般多進(jìn)程的事兒講到上面就完了,可是信號在系統(tǒng)中確實是一個非常重要的東西.信號就是信號燈,點亮一個信號燈,程序就會做出反應(yīng).這個你一定用過,好比說在終端下運行某個程序,等了半天也沒什么反應(yīng),可能你會按 Ctrl+C 來關(guān)閉這個程序.實際上,這里就是通過鍵盤向程序發(fā)送了一個中斷的信號:SIGINT.有時候進(jìn)程失去響應(yīng)了還會執(zhí)行kill [PID]命令,未加任何其他參數(shù)的話,程序會接收到一個SIGTERM信號.程序收到上面兩個信號的時候,默認(rèn)都會結(jié)束執(zhí)行,那么是否有可能改變這種默認(rèn)行為呢?必須能啊!PHP學(xué)習(xí)
4.1. 注冊信號PHP學(xué)習(xí)
人是活的程序也是活的,只不過程序必要遵循人制定的規(guī)則來運行.現(xiàn)在開始給信號重新設(shè)定規(guī)則,這里用到的函數(shù)是pcntl_signal()(繼續(xù)之前為啥不先查查PHP手冊呢?).下面這段程序?qū)⒔oSIGINT重新定義行為,注意看好:
PHP學(xué)習(xí)
4.2. 信號分發(fā)PHP學(xué)習(xí)
說明一下:pcntl_signal()函數(shù)僅僅是注冊信號和它的處理辦法,真正接收到信號并調(diào)用其處理辦法的是pcntl_signal_dispatch()函數(shù).試試把// do something替換成下面這段代碼:
PHP學(xué)習(xí)
4.3. 版本問題PHP學(xué)習(xí)
如果認(rèn)真看了PHP文檔,會發(fā)現(xiàn)pcntl_signal_dispatch()這個函數(shù)是PHP 5.3以上才支持的,如果你的PHP版本大于5.3,建議使用這個辦法調(diào)用信號處理器.5.3以下的版本需要在注冊信號之前加一句:declare(ticks = 1);表示每執(zhí)行一條低級指令,就檢查一次信號,如果檢測到注冊的信號,就調(diào)用其信號處理器.想想就挺不爽的,干嘛一直都檢查?還是在我們指定的地方檢查一下就好.PHP學(xué)習(xí)
4.4. 感受僵尸進(jìn)程PHP學(xué)習(xí)
現(xiàn)在我們回到子進(jìn)程回收的問題上(差點忘了= =").當(dāng)你的一個子進(jìn)程掛了(或者說是結(jié)束了),但是父進(jìn)程還在運行中并且可能很長一段時間不會退出.一個僵尸進(jìn)程從此站起來了!這時,掩護傘公司(內(nèi)核)發(fā)現(xiàn)它的地盤里出現(xiàn)了一個僵尸,這個僵尸是誰兒子呢?看一下PPID就知道了.然后,內(nèi)核給PPID這個進(jìn)程(也就是僵尸進(jìn)程的父進(jìn)程)發(fā)送一個信號:SIGCHLD.然后,你知道怎么在父進(jìn)程中回收這個子進(jìn)程了么?提示一下,用pcntl_wait()函數(shù).PHP學(xué)習(xí)
4.5. 發(fā)送信號PHP學(xué)習(xí)
希望剛剛有認(rèn)真man過kill命令.它其實就是向進(jìn)程發(fā)送信號,在PHP中也可以調(diào)用posix_kill()函數(shù)來達(dá)到相同的效果.有了它就可以在父進(jìn)程中控制其他子進(jìn)程的運行了.好比在父進(jìn)程結(jié)束之前關(guān)閉所有子進(jìn)程,那么fork的時候在父進(jìn)程記錄所有子進(jìn)程的PID,父進(jìn)程結(jié)束之前依次給子進(jìn)程發(fā)送結(jié)束信號即可.PHP學(xué)習(xí)
5. 實踐PHP學(xué)習(xí)
PHP的多進(jìn)程跟C還是挺像的,搞明白了以后用其他語言寫的話也大同小異差不多都是這么個情況.如果有空的話,測驗考試寫一個小程序,切身體會一下個中滋味:PHP學(xué)習(xí)
1.16歲的鳴人發(fā)送影分身,分出5個分身
2.每個分身隨機生存10到30秒,每秒都輸出點什么
3.保證原身能感受到分身的結(jié)束,然后開動另一個分身,保證最多有5個分身
4.不使用nohup,讓原身在終端關(guān)閉后依舊能夠運行
5.把分身數(shù)量(5)寫進(jìn)一個配置文件里,當(dāng)給原身發(fā)送信號(可以考慮用SIGUSR1或SIGUSR2)時,原身讀取配置文件并更新允許的分身最大數(shù)量
6.如果分身多了,關(guān)閉幾個;如果少了,再分出來幾個PHP學(xué)習(xí)
提示:PHP學(xué)習(xí)
1.用while循環(huán)保證進(jìn)程運行,注意sleep以免100%的CPU占用
2.運行進(jìn)程的終端被關(guān)閉時,法式會收到一個SIGHUP信號
3.可以用parse_ini_file()函數(shù)解析INI配置文件PHP學(xué)習(xí)
歡迎參與《PHP實戰(zhàn):PHP多進(jìn)程編程實例》討論,分享您的想法,維易PHP學(xué)院為您提供專業(yè)教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/14539.html