首頁  >  文章  >  後端開發  >  PHP實作多進程和多執行緒

PHP實作多進程和多執行緒

不言
不言原創
2018-05-03 11:07:142856瀏覽

這篇文章主要介紹了關於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上;

改善程式結構。一個既長又複雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程式會利於理解和修改。

1. [程式碼]PHP實作多進程並行作業(可做守護程式) 

/**
 * 入口函数
 * 将此文件保存为 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);
        }   
    }   
}

2. [程式碼]PHP實作多執行緒操作 

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 &#39;All thread end!&#39;;

相關推薦:

詳解PHP實作定時任務的五種方法


以上是PHP實作多進程和多執行緒的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn