<output id="r87xx"></output>
    1. 
      
      <mark id="r87xx"><thead id="r87xx"><input id="r87xx"></input></thead></mark>
        •   

               當前位置:首頁>軟件介紹>php多進程編程實例 查詢:
               
          php多進程編程實例

                   

                  PHP多進程編程實例

                  羨慕火影忍者里鳴人的影分身么,沒錯,PHP程序是可以開動影分身的~想完成任務,又覺得一個進程太慢,那么,試試用多進程來搞吧。這篇文章將會介紹一下PHP多進程的基本需求,如何創(chuàng)建多進程以及基本的信號控制,暫時不會告訴你如何進行進程間通信和信息共享。

                  1. 準備

                  在動手之前,請確定你用的不是M$ Windows平臺(因為我沒有Windows)。Linux / BSD / Unix

                  應該都是沒問題的。確認好了工作環(huán)境以后一起來看看我們需要的PHP模塊是否都有。打開終端輸入下面的命令:

                  代碼如下:

                  $ php -m

                  這個命令檢查并打印當前PHP所有開啟的擴展,看一下pcntl和posix是否在輸出的列表中。

                  1.1. pcntl

                  如果找不到pcntl,八成是編譯的時候沒把這個擴展編譯進去。如果你和我一樣是編譯安裝的PHP,那么需要重新編譯安裝PHP。在配置的時候記得加上--enable-pcntl參數即可。 代碼如下:

                  $ cd /path/to/php_source_code_dir $ ./configure [some other options] --enable-pcntl

                  $ make &amp;&amp; make install

                  1.2. posix

                  這貨一般默認就會裝上,只要你編譯的時候沒有加上--disable-posix。

                  2. 預備知識

                  在繼續(xù)之前,你還需要對Linux多進程有一點了解。多進程是咋回事呢,這里可跟火影忍者里的影分身稍微有點不同。首先,鳴人從小長到大,比如16歲,咳。有一天他發(fā)動了影分身,分出了5個他。顯然,這些分身也是16歲的鳴人而不是剛出生啥也不懂就會哭的嬰兒(那叫克隆)。然后,不一樣的地方來了:分身們變成了獨立的人各自去做各自的事,互相之間不再知道其他分身和原身都做了什么(當然不會像動畫片里一樣積累經驗給原身啦)。除非,他們互相之間有交流,不然,只有16歲之前的事情才是他們共同的記憶。 有同學說了,老大你這不坑爹呢么,我又沒看過火影忍者~那你去看一遍好了…… 最后,預備知識完了,就是大致了解一下主進程開出來的子進程是怎么回事。子進程的代碼和主進程是完全一樣的,還有一部分一樣的東西就是直到發(fā)動影分身之前執(zhí)行的所有內容。 3. 影分身之術

                  所以呢,沒有點基礎知識怎么能理解卷軸里的內容呢,打開卷軸首先看到了一個單詞:fork。

                  3.1. fork

                  叉子,叉子是分岔的,一個變多個嘛~差不多就是這個意思。創(chuàng)建子進程就用這個命令。這里需要用到pcntl_fork()函數。(可以先簡單看一下PHP手冊關于這個函數的介紹。)創(chuàng)建一個PHP腳本:

                  代碼如下:

                  $pid = pcntl_fork(); // 一旦調用成功,事情就變得有些不同了

                  if ($pid == -1) {

                  die('fork failed');

                  } else if ($pid == 0) {

                  } else {

                  }

                  pcntl_fork()函數創(chuàng)建一個子進程,子進程和父進程唯一的區(qū)別就是PID(進程ID)和PPID(父進程ID)不同。在終端下查看進程用ps命令(問問man看ps怎么用:man ps)。當函數返回值為-1的時候,說明fork失敗了。試試在if前面加一句:echo $pid . PHP_EOL;。運行你的腳本,輸出可能像下面這樣(結果說明子進程和父進程的代碼是相同的): 代碼如下:

                  67789 # 這個是父進程打印的

                  0 # 這個是子進程打印的

                  pcntl_fork()函數調用成功后,在父進程中會返回子進程的PID,而在子進程中返回的是0。所以,下面直接用if分支來控制父進程和子進程做不同的事。

                  3.2. 分配任務

                  然后我們來說說鳴人16歲那次影分身的事兒,給原身和分身分配兩個簡單的輸出任務: 代碼如下:

                  $parentPid = getmypid(); // 這就是傳說中16歲之前的記憶

                  $pid = pcntl_fork(); // 一旦調用成功,事情就變得有些不同了

                  if ($pid == -1) {

                  die('fork failed');

                  } else if ($pid == 0) {

                  $mypid = getmypid(); // 用getmypid()函數獲取當前進程的PID

                  echo 'I am child process. My PID is ' . $mypid . ' and my father's PID is ' . $parentPid . PHP_EOL;

                  } else {

                  echo 'Oh my god! I am a father now! My child's PID is ' . $pid . ' and mine is ' . $parentPid .

                  PHP_EOL;

                  }

                  輸出的結果可能是這樣:

                  代碼如下:

                  Oh my god! I am a father now! My child's PID is 68066 and mine is 68065

                  I am child process. My PID is 68066 and my father's PID is 68065

                  再強調一下,pcntl_fork()調用成功以后,一個程序變成了兩個程序:一個程序得到的$pid變量值是0,它是子進程;另一個程序得到的$pid的值大于0,這個值是子進程的PID,它是父進程。在下面的分支語句中,由于$pid值的不同,運行了不同的代碼。再次強調一下:子進程的代碼和父進程的是一樣的。所以就要通過分支語句給他們分配不同的任務。

                  3.3. 子進程回收

                  剛剛有man ps么,一般我習慣用ps aux加上grep命令來查找運行著的后臺進程。其中有一列STAT,標識了每個進程的運行狀態(tài)。這里,我們關注狀態(tài)Z:僵尸(Zombie)。當子進程比父進程先退出,而父進程沒對其做任何處理的時候,子進程將會變成僵尸進程。Oops,又跟火影里的影分身不一樣了。鳴人的影分身被干死了以后就自動消失了,但是這里的子進程分身死了話還留著一個空殼在,直到父進程回收它。僵尸進程雖然不占什么內存,但是很礙眼,院子里一堆躺著的僵尸怎么都覺得怪怪的。(別忘了它們還占用著PID) 一般來說,在父進程結束之前回收掛掉的子進程就可以了。在pcntl擴展里面有一個pcntl_wait()函數,它會將父進程掛起,直到有一個子進程退出為止。如果有一個子進程變成了僵尸的話,它會立即返回。所有的子進程都要回收,所以多等等也沒關系啦~

                  3.4. 父進程先掛了

                  如果父進程先掛了怎么辦,會發(fā)生什么,什么也不會發(fā)生,子進程依舊還在運行。但是這個時候,子進程會被交給1號進程,1號進程成為了這些子進程的繼父。1號進程會很好地處理這些進程的資源,當它們結束時1號進程會自動回收資源。所以,另一種處理僵尸進程的臨時辦法是關閉它們的父進程。

                  4. 信號

                  一般多進程的事兒講到上面就完了,可是信號在系統(tǒng)中確實是一個非常重要的東西。信號就是信號燈,點亮一個信號燈,程序就會做出反應。這個你一定用過,比如說在終端下運行某個程序,等了半天也沒什么反應,可能你會按 Ctrl+C 來關閉這個程序。實際上,這里就是通過鍵盤向程序發(fā)送了一個中斷的信號:SIGINT。有時候進程失去響應了還會執(zhí)行kill [PID]命令,未加任何其他參數的話,程序會接收到一個SIGTERM信號。程序收到上面兩個信號的時候,默認都會結束執(zhí)行,那么是否有可能改變這種默認行為呢,必須能啊~

                  4.1. 注冊信號

                  人是活的程序也是活的,只不過程序需要遵循人制定的規(guī)則來運行。現在開始給信號重新設定規(guī)則,這里用到的函數是pcntl_signal()(繼續(xù)之前為啥不先查查PHP手冊呢,)。下面這段程序將給SIGINT重新定義行為,注意看好:

                  代碼如下:

                  // 定義一個處理器,接收到SIGINT信號后只輸出一行信息

                  function signalHandler($signal) { if ($signal == SIGINT) {

                  echo 'signal received' . PHP_EOL; }

                  }

                  // 信號注冊:當接收到SIGINT信號時,調用signalHandler()函數

                  pcntl_signal(SIGINT, 'signalHandler'); while (true) {

                  sleep(1);

                  // do something

                  pcntl_signal_dispatch(); // 接收到信號時,調用注冊的signalHandler() }

                  執(zhí)行一下,隨時按下 Ctrl+C 看看會發(fā)生什么事。

                  4.2. 信號分發(fā)

                  說明一下:pcntl_signal()函數僅僅是注冊信號和它的處理方法,真正接收到信號并調用其處理方法的是pcntl_signal_dispatch()函數。試試把// do something替換成下面這段代碼: 代碼如下:

                  for ($i = 0; $i 1000000; $i++) { echo $i . PHP_EOL;

                  usleep(100000);

                  }

                  在終端下執(zhí)行這個腳本,當它不停輸出數字的時候嘗試按下 Ctrl+C ??纯闯绦蛴惺?declare(ticks = 1);表示每執(zhí)行一條低級指令,就檢查一次信號,如果檢測到注冊的信號,就調用其信號處理器。想想就挺不爽的,干嘛一直都檢查,還是在我們指定的地方檢查一下就好。

                  4.4. 感受僵尸進程

                  現在我們回到子進程回收的問題上(差點忘了= =")。當你的一個子進程掛了(或者說是結束了),但是父進程還在運行中并且可能很長一段時間不會退出。一個僵尸進程從此站起來了~這時,保護傘公司(內核)發(fā)現它的地盤里出現了一個僵尸,這個僵尸是誰兒子呢,看一下PPID就知道了。然后,內核給PPID這個進程(也就是僵尸進程的父進程)發(fā)送一個信號:SIGCHLD。然后,你知道怎么在父進程中回收這個子進程了么,提示一下,用pcntl_wait()函數。

                  4.5. 發(fā)送信號

                  希望剛剛有認真man過kill命令。它其實就是向進程發(fā)送信號,在PHP中也可以調用posix_kill()函數來達到相同的效果。有了它就可以在父進程中控制其他子進程的運行了。比如在父進程結束之前關閉所有子進程,那么fork的時候在父進程記錄所有子進程的PID,父進程結束之前依次給子進程發(fā)送結束信號即可。

                  5. 實踐

                  PHP的多進程跟C還是挺像的,搞明白了以后用其他語言寫的話也大同小異差不多都是這么個情況。如果有空的話,嘗試寫一個小程序,切身體會一下個中滋味: 1.16歲的鳴人發(fā)送影分身,分出5個分身

                  2.每個分身隨機生存10到30秒,每秒都輸出點什么

                  3.保證原身能感受到分身的結束,然后開動另一個分身,保證最多有5個分身 4.不使用nohup,讓原身在終端關閉后依舊能夠運行

                  5.把分身數量(5)寫進一個配置文件里,當給原身發(fā)送信號(可以考慮用SIGUSR1或SIGUSR2)時,原身讀取配置文件并更新允許的分身最大數量

                  6.如果分身多了,關閉幾個;如果少了,再分出來幾個提示:

                  1.用while循環(huán)保證進程運行,注意sleep以免100%的CPU占用

                  2.運行進程的終端被關閉時,程序會收到一個SIGHUP信號

                  3.可以用parse_ini_file()函數解析INI配置文件

                  


          PHP安裝說明PHP是一種腳本語言最初產生動態(tài)網頁設計
          php用ftp遠程上傳文件PHP json_encode() 函數取值介紹
          php面向對象的程序設計php函數快速查詢
          PHP購物車類Cart.class.php定義與用法php加iis服務器搭建PHP的運行環(huán)境
          PHP實例說明編寫PHP代碼的5個好習慣提高PHP編程效率引入緩存機制提升性能
          如何在本地搭建php環(huán)境PHP陽歷轉農歷的類
          PHP模板引擎smarty進門PHP中多態(tài)如何實現
          PHP執(zhí)行系統(tǒng)外部命令通過 PDO 將 PHP 連接到 DB2 和 Cloudscape
          信息發(fā)布:廣州名易軟件有限公司 http://www.jetlc.com
          • 勁爆價:
            不限功能
            不限用戶
            1998元/年

          • 微信客服

            <output id="r87xx"></output>
          1. 
            
            <mark id="r87xx"><thead id="r87xx"><input id="r87xx"></input></thead></mark>
              • 淫欲少妇做爱高潮视频 | 亚洲成人黄色视频 | 国产18页| aaa三级片久久久 | 青娱乐在线视频精品 | 国产在线视频卡一卡二 | 亚洲高清五码视频 | 三级经典欧美大战高潮 | 播播影院在线特别黄色视频看看你 | aa在线免费观看 |