久久久久无码精品,四川省少妇一级毛片,老老熟妇xxxxhd,人妻无码少妇一区二区

php多進(jìn)程編程詳解

時(shí)間:2024-06-04 20:24:10 PHP 我要投稿
  • 相關(guān)推薦

php多進(jìn)程編程詳解2017

  日常任務(wù)中,有時(shí)需要通過php腳本執(zhí)行一些日志分析,隊(duì)列處理等任務(wù),當(dāng)數(shù)據(jù)量比較大時(shí),可以使用多進(jìn)程來處理。php多進(jìn)程是怎么寫的?下面yjbys小編為大家分享php多進(jìn)程編程,希望對(duì)大家有參考作用!

  php單進(jìn)程存在的問題:

  多核處理器未充分利用,而單處理器通常需要等待其他操作完成之后才能再繼續(xù)工作。 任何現(xiàn)代操作系統(tǒng)都可在幕后執(zhí)行多任務(wù),這意味著在很短時(shí)間內(nèi),計(jì)算機(jī)可以調(diào)度多個(gè)進(jìn)程,以執(zhí)行多個(gè)程序。

  如果我們將所有的工作都局限在一個(gè)進(jìn)程中,它只能一次做一件事,這意味著我們需要將我們的單進(jìn)程任務(wù)變成一個(gè)多進(jìn)程任務(wù),以便我們可以利用 操作系統(tǒng)的多任務(wù)處理能力。

  多進(jìn)程與多線程

  在繼續(xù)之前,先解釋下多進(jìn)程和多線程之間的區(qū)別。

  進(jìn)程,是具有其自己的存儲(chǔ)器空間,自己的進(jìn)程ID號(hào)等的程序的唯一實(shí)例。

  線程,可以被認(rèn)為是一個(gè)虛擬進(jìn)程,它沒有自己的進(jìn)程ID,沒有自己的內(nèi)存空間,但仍然能夠利用多任務(wù)。

  啟用超線程的CPU,通過動(dòng)態(tài)生成線程,以盡可能避免延遲,從而進(jìn)一步推進(jìn)。

  雖然有些人可能不同意,但大多數(shù)Unix程序員具有一定程度的不信任的線程。 Unix系統(tǒng)總是首選多進(jìn)程,然后才是多線程,部分原因是在Unix上創(chuàng)建一個(gè)進(jìn)程(通常稱為子進(jìn)程的“生成”或“分叉”)是非?斓。 在其他操作系統(tǒng)中,如Windows,fork相當(dāng)慢,所以線程概念更受歡迎。

  考慮到這一點(diǎn),毫不奇怪,所以目前只有在unix系統(tǒng)中支持php以fork多個(gè)進(jìn)程,這個(gè)擴(kuò)展是pcntl_fork函數(shù)

  php如何進(jìn)行多進(jìn)程編程

  在php中使用pcntl_fork擴(kuò)展函數(shù)進(jìn)行frok多個(gè)進(jìn)程。

  pcntl_fork返回值說明

  當(dāng)pcntl_fork函數(shù)被調(diào)用時(shí),它將返回3個(gè)值。

  如果返回值為-1,則fork失敗,并且沒有子進(jìn)程。 這可能是由于缺少內(nèi)存,或者因?yàn)橐呀?jīng)達(dá)到對(duì)用戶進(jìn)程數(shù)量的系統(tǒng)限制。

  如果返回值是大于0的任何數(shù)字,當(dāng)前腳本是調(diào)用pcntl_fork()的父級(jí),返回值是分叉的子進(jìn)程的進(jìn)程ID(PID)。 最后,如果返回值為0,則當(dāng)前腳本是被分叉的子節(jié)點(diǎn)。

  pcntl_fork執(zhí)行原理

  如果你成功的執(zhí)行pcntl_fork()函數(shù),將有兩個(gè)PHP副本同時(shí)執(zhí)行相同的腳本。 它們都從pcntl_fork()行繼續(xù)執(zhí)行,最重要的是,子進(jìn)程獲取父進(jìn)程中設(shè)置的所有變量的副本,甚至是資源。 我們忘記的一個(gè)關(guān)鍵的事情是,資源的副本不是一個(gè)獨(dú)立的資源,他們將指向同一個(gè)事情,這可能是有問題的,更多的詳情,稍后將繼續(xù)討論。

  現(xiàn)在,這里有一個(gè)基本使用pcntl_fork()的例子:

  <?php

  $pid = pcntl_fork();    switch($pid) {        case -1:            print "Could not fork!\n";            exit;        case 0:            print "In child!\n";            break;        default:            print "In parent!\n";

  }?>

  上面的腳本只是在父進(jìn)程和子進(jìn)程中打印一條消息。 但是,它不顯示父項(xiàng)的變量數(shù)據(jù)如何被復(fù)制到子項(xiàng),它輸出了2條信息,如下所示,說明已經(jīng)是有2個(gè)進(jìn)程在執(zhí)行了(其中一個(gè)是主進(jìn)程,一個(gè)是fork出來的子進(jìn)程)

  [root@25f0b49dc696 wwwroot]# php fork.php In parent!In child!

  接著看下面的例子:

  <?php

  $pid1 = pcntl_fork(); //第一次fork

  $pid2 = pcntl_fork(); //第二次fork

  $pid3 = pcntl_fork(); //第三次fork

  $current_process_id = posix_getpid();

  echo "current_process_id===$current_process_id===pid1==$pid1===pid2===$pid2==pid3==$pid3\n";

  上面的例子,輸出結(jié)果如下:

  current_process_id===13090===pid1==13091===pid2===13092==pid3==13093current_process_id===13093===pid1==13091===pid2===13092==pid3==0current_process_id===13092===pid1==13091===pid2===0==pid3==13094current_process_id===13094===pid1==13091===pid2===0==pid3==0current_process_id===13091===pid1==0===pid2===13095==pid3==13096current_process_id===13096===pid1==0===pid2===13095==pid3==0current_process_id===13095===pid1==0===pid2===0==pid3==13097current_process_id===13097===pid1==0===pid2===0==pid3==0

  分析上面的結(jié)果,

  可以看出,主進(jìn)程ID是13090

  第一次fork

  主13090 ->13091

  第二次fork

  主13090 ->13092

  子13091 ->13095

  第三次fork

  主13090 ->13093

  子13091 ->13096

  子13092 ->13094

  子13095 ->13097

  至此,一共有8個(gè)進(jìn)程在執(zhí)行當(dāng)前腳本

  接著看下面的例子:

  <?php

  $main_process_id = posix_getpid();

  echo "the main process id==$main_process_id\n";    for ($i = 1; $i <= 5; ++$i) {

  $pid = pcntl_fork();

  $current_process_id = posix_getpid();        if (!$pid) {

  echo "child $i current process id==$current_process_id==pid==$pid\n";            sleep(1);            //sleep($i)            print "In child $i\n";            //這里設(shè)置sleep不會(huì)阻塞輸出,1s后會(huì)自動(dòng)結(jié)束進(jìn)程

  //sleep(1);            //結(jié)束當(dāng)前子進(jìn)程,不讓子進(jìn)程繼續(xù)fork,不會(huì)阻止父進(jìn)程繼續(xù)fork

  exit;

  }        else{

  echo "parent current process id==$current_process_id==pid==$pid\n";            print "In parent $i\n";            //fork完畢,退出父進(jìn)程,不讓下次參與fork,能保證執(zhí)行順序,但下一次的fork要等待子進(jìn)程執(zhí)行完成后才能fork

  //exit;

  }

  }

  這次五個(gè)子進(jìn)程被fork創(chuàng)建成功,并且,因?yàn)槊總(gè)子進(jìn)程在父進(jìn)程最后設(shè)置的時(shí)候獲取$ i變量的副本,腳本打印出"In child 1", "In child 2", "In child 3", "In child 4", and "In child 5".

  [root@25f0b49dc696 wwwroot]# php fork2.php the main process id==13163parent current process id==13163==pid==13164In parent 1parent current process id==13163==pid==13165In parent 2parent current process id==13163==pid==13166In parent 3parent current process id==13163==pid==13167In parent 4parent current process id==13163==pid==13168In parent 5child 3 current process id==13166==pid==0child 2 current process id==13165==pid==0child 4 current process id==13167==pid==0child 5 current process id==13168==pid==0child 1 current process id==13164==pid==0[root@25f0b49dc696 wwwroot]# In child 3In child 4In child 5In child 2In child 1

  然而,一切都不是那么簡(jiǎn)單,因?yàn)橛袃蓚(gè)關(guān)鍵的事情要注意,當(dāng)你運(yùn)行上述腳本。

  首先,注意每個(gè)子腳本在打印出它的消息后調(diào)用exit。 在正常情況下,這將立即退出腳本,但在這里,它退出的是子PHP腳本,而不是父或任何其他子腳本。因此,每個(gè)其他子腳本和父腳本可以并且確實(shí)在一個(gè)孩子終止后繼續(xù)執(zhí)行。

  其次,當(dāng)腳本運(yùn)行時(shí),它的輸出可能很混亂。

  注意孩子們?nèi)绾伟错樞虼蛴〕鏊麄兊男畔ⅰ?雖然這可能是很常見的情況,你不能依靠你的孩子被執(zhí)行在一個(gè)特定的順序。

  這是多處理器的基本原則之一:一旦產(chǎn)生了進(jìn)程,它就是操作系統(tǒng)決定何時(shí)執(zhí)行它以及給出多少時(shí)間。

  還要注意我如何立即返回到我的shell提示,然后調(diào)用五個(gè)孩子打印出他們的消息,盡管我顯然已經(jīng)有控制權(quán)。

  這樣做的原因是因?yàn)殡m然孩子們附著在終端上,但他們基本上是在后臺(tái)運(yùn)行的。 一旦父終止,命令提示符將重新出現(xiàn),你可以開始執(zhí)行其他程序,但是,正如你可以看到,孩子們?nèi)匀粫?huì)活躍,當(dāng)他們想(因?yàn)楹⒆觽儾粫?huì)做)。 在沒有sleep命令情況下,這將不那么明顯,但是重要的是記住子進(jìn)程本質(zhì)上有自己的運(yùn)行環(huán)境。

  PHP,像任何父母,可以使其監(jiān)視其孩子,以確保他們做正確的事情。 這是通過兩個(gè)新函數(shù)來實(shí)現(xiàn)的:

  pcntl_waitpid(),它指示PHP等待子進(jìn)程,

  pcntl_wexitstatus(),它獲取一個(gè)終止子進(jìn)程返回的值。 我們已經(jīng)看過exit()函數(shù),以及如何使用它來向系統(tǒng)返回一個(gè)值

  我們將使用這個(gè)值將值發(fā)送回父進(jìn)程,然后檢索使用pcntl_wexitstatus()。

  在深入了解代碼之前,讓我先解釋一下這些新函數(shù)是如何使用的。

  pcntl_waitpid

  int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )

  默認(rèn)情況下,pcntl_waitpid()將導(dǎo)致父進(jìn)程無限期地暫停,等待子進(jìn)程終止。

  如果pid指定的子進(jìn)程在此函數(shù)調(diào)用時(shí)已經(jīng)退出(俗稱僵尸進(jìn)程),此函數(shù) 將立刻返回

  至少需要兩個(gè)參數(shù),$pid-父類應(yīng)該等待的子進(jìn)程ID,$status-用來填充子進(jìn)程狀態(tài)的變量

  $pid的值可以是以下之一:

  < -1    等待任意進(jìn)程組ID等于參數(shù)pid給定值的絕對(duì)值的進(jìn)程。例如,如果傳遞-1802,pcntl_waitpid將等待進(jìn)程組ID為1802的任何子進(jìn)程。-1  等待任意子進(jìn)程;與pcntl_wait函數(shù)行為一致。0   等待任意與調(diào)用進(jìn)程組ID相同的子進(jìn)程。這是最常用的值。

  > 0 等待進(jìn)程號(hào)等于參數(shù)pid值的子進(jìn)程。也就是說,如果你傳入1802,pcntl_waitpid將等待子進(jìn)程1802終止。

  $status

  pcntl_waitpid()將會(huì)存儲(chǔ)狀態(tài)信息到status 參數(shù)上,這個(gè)通過status參數(shù)返回的狀態(tài)信息可以用以下函數(shù) pcntl_wifexited(), pcntl_wifstopped(), pcntl_wifsignaled(), pcntl_wexitstatus(), pcntl_wtermsig()以及 pcntl_wstopsig()獲取其具體的值。

  返回值

  pcntl_waitpid()返回退出的子進(jìn)程進(jìn)程號(hào),發(fā)生錯(cuò)誤時(shí)返回-1

  返回終止子進(jìn)程的PID,然后用狀態(tài)變量填充子進(jìn)程退出的信息。

  如果調(diào)用pcntl_waitpid并且沒有子運(yùn)行,則立即返回-1并且不填充狀態(tài)變量。

  因此,如果0作為第一個(gè)參數(shù)傳遞給函數(shù),pcntl_waitpid()將等待它的任何子進(jìn)程終止。 當(dāng)它成立時(shí),它返回子進(jìn)程的PID,終止并填充第二個(gè)參數(shù),并提供有關(guān)終止的子進(jìn)程的信息。 因?yàn)槲覀冇袔讉(gè)孩子,我們需要繼續(xù)調(diào)用pcntl_waitpid(),直到它返回-1,每次返回一些東西,我們應(yīng)該打印出來的子進(jìn)程的返回值。

  從我們的子進(jìn)程返回一個(gè)值就像向exit()傳遞一個(gè)參數(shù)一樣簡(jiǎn)單,而不僅僅是終止。 這通過pcntl_waitpid()的返回值返回父節(jié)點(diǎn),返回一個(gè)狀態(tài)代碼。 此狀態(tài)代碼不直接求值為返回值,因?yàn)樗瑑蓚(gè)位的信息:子節(jié)點(diǎn)如何終止,以及如果子節(jié)點(diǎn)終止,則返回它的退出代碼。

  現(xiàn)在我們只假設(shè)子節(jié)點(diǎn)自己終止,這意味著退出代碼總是設(shè)置在pcntl_waitpid()的返回值里面。 要從返回值提取退出代碼,使用pcntl_wexitstatus()函數(shù),它將返回值作為其唯一參數(shù),并返回子進(jìn)程的退出代碼。

  這可能聽起來很復(fù)雜,但是一旦查看下一個(gè)代碼項(xiàng)目,它應(yīng)該會(huì)變得清楚。 這個(gè)例子顯示了我們討論的一切:

  <?php    for ($i = 1; $i <= 5; ++$i) {

  $pid = pcntl_fork();        if (!$pid) {            sleep(1);

  $current_process_id = posix_getpid();            print "In child $i===process_id===$current_process_id\n";            exit($i);

  }

  }    while (($pid = pcntl_waitpid(0, $status)) != -1) {

  $status = pcntl_wexitstatus($status);

  echo "Child $status completed==pid==$pid\n";

  }

  ?>

  上例將輸出,同時(shí)也驗(yàn)證了pcntl_waitpid返回的pid是正確的

  In child 1===process_id===13106In child 5===process_id===13110In child 4===process_id===13109In child 3===process_id===13108In child 2===process_id===13107Child 4 completed==pid==13109Child 5 completed==pid==13110Child 1 completed==pid==13106Child 3 completed==pid==13108Child 2 completed==pid==13107

  注意,通過使用exit($ i);每個(gè)子節(jié)點(diǎn)返回它在屏幕上打印出來的數(shù)字作為其退出代碼。 主while循環(huán)再次調(diào)用pcntl_waitpid(),直到它返回-1(沒有子節(jié)點(diǎn)),并且對(duì)于每個(gè)終止的子節(jié)點(diǎn),它使用pcntl_wexitstatus()提取出口代碼并打印出來。 注意,pcntl_waitpid()的第一個(gè)參數(shù)是0,這意味著它將等待所有的孩子。

  運(yùn)行該腳本應(yīng)該停止命令提示符,直到所有五個(gè)孩子終止,這是理想的。

【php多進(jìn)程編程詳解】相關(guān)文章:

 PHP的基礎(chǔ)編程與應(yīng)用04-01

《PHP編程最快明白》第八講:php啟發(fā)和小結(jié)03-31

關(guān)于編程之PHP常用MySql操作的方法04-02

關(guān)于深入PHP內(nèi)存相關(guān)的功能特性詳解04-01

多進(jìn)程OSPF及進(jìn)程號(hào)的意義03-30

關(guān)于php面試寶典及PHP面試技巧04-02

PHP的壓縮函數(shù)03-31

php高級(jí)教程01-23

數(shù)控編程的技巧03-25