這篇文章主要介紹了關於PHP實現多進程和多線程,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
菜鳥須知:
孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成為孤兒進程。孤兒進程將被init進程(進程編號為1)所收養,並由init進程對它們完成狀態收集工作。
殭屍進程:一個進程使用fork建立子進程,如果子進程退出,而父進程並沒有呼叫wait或waitpid取得子進程的狀態信息,那麼子進程的進程描述符仍然保存在系統中。這種進程稱之為僵死進程。
殭屍行程危害:如果行程不呼叫wait / waitpid的話,
##那麼保留的那段資訊就不會釋放,其進程號就會一直被佔用,但是系統所能使用的進程號是有限的,如果大量的產生僵死進程,將因為沒有可用的進程號而導致系統不能產生新的進程. 此即為殭屍進程的危害,應當避免。 任何一個子程序(init除外)在exit()之後,並非馬上就消失掉,而是留下一個稱為殭屍進程(Zombie)的資料結構,等待父程序處理。
已經產生的殭屍進程,解決方法:
kill掉父進程,它產生的僵死進程就變成了孤兒進程,這些孤兒進程會被init進程接管,init進程會wait()這些孤兒進程,釋放它們佔用的系統進程表中的資源。
殭屍流程解決方法
(1)透過訊號機制
# 子程序退出時向父行程發送SIGCHILD訊號,父行程處理SIGCHILD訊號。在訊號處理函數中呼叫wait進行處理殭屍程序。
(2)fork兩次
# 《Unix 環境進階程式設計》8.6節所說的非常詳細。原理是將子進程成為孤兒進程,從而其的父進程變成init進程,透過init進程可以處理殭屍進程。
多重行程與多執行緒比較
|
比較維度 |
多行程 |
多執行緒 |
總結 |
#######資料共享、同步########## ##資料共享複雜,需要用IPC;資料是分開的,同步簡單### | 因為共享進程數據,資料共享簡單,但也是因為這個原因導致同步複雜 |
各有優勢 |
記憶體、CPU |
佔用記憶體多,切換複雜,CPU利用率低 |
佔用記憶體少,切換簡單,CPU利用率高 |
執行緒佔優 |
#建立銷毀、切換 |
創建銷毀、切換複雜,速度慢 |
創建銷毀、切換簡單,速度很快 |
線程佔優 |
程式設計、偵錯 |
程式簡單,偵錯簡單 |
程式設計複雜,調試複雜 |
進程佔優 |
可靠性 |
|||
##進程間不會互相影響 | 一個執行緒掛掉會導致整個行程掛掉 進程佔優 |
1)需要經常建立銷毀的優先用執行緒
原因請看上面的比較。
這種原則最常見的應用就是Web伺服器了,來一個連接建立一個線程,斷了就銷毀線程,要是用進程,創建和銷毀的代價是很難承受的
2)需要進行大量計算的優先使用線程
所謂大量計算,當然就是要耗費很多CPU,切換頻繁了,這種情況下線程是最合適的。
這種原則最常見的是影像處理、演算法處理。
3)強相關的處理用線程,弱相關的處理用進程
什麼叫強相關、弱相關?理論上很難定義,給個簡單的例子就明白了。
一般的Server需要完成以下任務:訊息收發、訊息處理。 “訊息收發”和“訊息處理”就是弱相關的任務,而“訊息處理”裡面可能又分為“訊息解碼”、“業務處理”,這兩個任務相對來說相關性就要強多了。因此「訊息收發」和「訊息處理」可以分進程設計,「訊息解碼」、「業務處理」可以分線程設計。
當然這種劃分方式不是一成不變的,也可以依照實際情況來調整。
4)可能要擴展到多機分佈的用進程,多核心分佈的用執行緒
原因請看上面比較。
5)都滿足需求的情況下,用你最熟悉、最拿手的方式
至於「資料共享、同步」、「程式設計、調試」、 「可靠性」這幾個維度的所謂的「複雜、簡單」應該怎麼取捨,我只能說:沒有明確的選擇方法。但我可以告訴你一個選擇原則:如果多進程和多執行緒都能夠滿足要求,那麼就選擇你最熟悉、最拿手的那個。
需要提醒的是:雖然我給了這麼多的選擇原則,但實際應用中基本上都是「進程線程」的結合方式,千萬不要真的陷入一種非此即彼的誤區。
消耗資源:
從核心的觀點來看,行程的目的就是擔當分配系統資源(CPU時間、記憶體等)的基本單位。執行緒是進程的一個執行流,是CPU調度和分派的基本單位,它是比進程更小的能獨立運作的基本單位。
線程,它們彼此之間使用相同的地址空間,共享大部分數據,啟動一個線程所花費的空間遠遠小於啟動一個進程所花費的空間,而且,線程間彼此切換所需的時間也遠遠小於進程間切換所需的時間。根據統計,總的說來,一個行程的開銷大約是一個執行緒開銷的30倍左右,當然,在具體的系統上,這個資料可能會有較大的差異。
通訊方式:
進程之間傳遞資料只能是透過通訊的方式,即費時又不方便。線程時間資料大部分共享(線程函數內部不共享),快速方便。但是資料同步需要鎖定對於static變數尤其註意
線程自身優勢:
#提高應用程式回應;使多CPU系統更加有效。 作業系統會保證當執行緒數不大於CPU數目時,不同的執行緒運行於不同的CPU上;
改善程式結構。一個既長又複雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程式會利於理解和修改。
/** * 入口函数 * 将此文件保存为 ProcessOpera.php * 在terminal中运行 /usr/local/php/bin/php ProcessOpera.php & * 查看进程 ps aux|grep php */ ProcessOpera("runCode", array(), 8); /** * run Code */ function runCode($opt = array()) { //需要在守护进程中运行的代码 } /** * $func为子进程执行具体事物的函数名称 * $opt为$func的参数 数组形式 * $pNum 为fork的子进程数量 */ function ProcessOpera($func, $opts = array(), $pNum = 1) { while(true) { $pid = pcntl_fork(); if($pid == -1) { exit("pid fork error"); } if($pid) { static $execute = 0; $execute++; if($execute >= $pNum) { pcntl_wait($status); $execute--; } } else { while(true) { //somecode $func($opts); sleep(1); } exit(0); } } }
class My extends Thread { protected $name; public $runing; function __construct($name){ $this->runing=1; $this->param=0; $this->name=$name; } public function run() { while($this->runing){ if($this->param){ $time=rand(1,5); echo 'I am thread '.$this->name.',pid: '.$this->getCreatorId().",param: {$this->param},need {$time}s\n"; sleep($time); $this->param=0; }else{ echo "Thread {$this->name} waiting...\n"; } sleep(1); } } } $pool=array(); $pool[]=new My('a'); $pool[]=new My('b'); $pool[]=new My('c'); //开启所有线程 foreach ($pool as $w) { $w->start(); } //派发任务 unset($w); for($i=1;$i<10;$i++){ $woker_content=$i; while(1){ foreach($pool as $w){ if(!$w->param){ $w->param=$woker_content; echo "Thread {$w->name} empty,put param {$woker_content}.\n"; break 2; } } sleep(1); } } unset($w); while(count($pool)){ foreach ($pool as $k => $w) { if(!$w->param){ $w->runing=false; unset($pool[$k]); echo "Thread {$w->name} end,exit!\n"; } } sleep(1); } echo 'All thread end!';
相關推薦:
以上是PHP實作多進程和多執行緒的詳細內容。更多資訊請關注PHP中文網其他相關文章!