欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入探究PHP的多進(jìn)程編程方法

 更新時(shí)間:2015年08月18日 16:04:30   作者:Junn  
這篇文章主要介紹了深入探究PHP的多進(jìn)程編程方法,同時(shí)介紹了Windows系統(tǒng)下的多線程嘗試,是PHP并發(fā)實(shí)現(xiàn)方面的重要內(nèi)容,需要的朋友可以參考下

子進(jìn)程的創(chuàng)建
一般的子進(jìn)程的寫法是:

<?php
$pid = pcntl_fork();
if($pid == -1){
     //創(chuàng)建失敗
     die('could not fork');
}
else{
    if($pid){
        //從這里開始寫的代碼是父進(jìn)程的
        exit("parent!");
    }
    else{
        //子進(jìn)程代碼,為防止不停的啟用子進(jìn)程造成系統(tǒng)資源被耗盡的情況,一般子進(jìn)程代碼運(yùn)行完成后,加入exit來確保子進(jìn)程正常退出。
        exit("child");
    }
}
?>

    上邊的代碼如果創(chuàng)建子進(jìn)程成功的話,系統(tǒng)就有了2個(gè)進(jìn)程,一個(gè)為父進(jìn)程,一個(gè)為子進(jìn)程,子進(jìn)程的id號(hào)為$pid。在系統(tǒng)運(yùn)行到$pid = pcntl_fork();時(shí),在這個(gè)地方進(jìn)行分支,父子進(jìn)程各自開始運(yùn)行各自的程序代碼。代碼的運(yùn)行結(jié)果是parent 和child,很奇怪吧,為什么一個(gè)if和else互斥的代碼中,都輸出了結(jié)果?其實(shí)是像上邊所說的,代碼在pcntl_fork時(shí),一個(gè)父進(jìn)程運(yùn)行parent,一個(gè)子進(jìn)程運(yùn)行了child。在代碼結(jié)果上就顯示了parent和child。至于誰先誰后的問題,這得要看系統(tǒng)資源的分配了。

    如果需要起多個(gè)進(jìn)程來處理數(shù)據(jù),可以根據(jù)數(shù)據(jù)的數(shù)量,按照約定好的數(shù)量比如說1000條一個(gè)進(jìn)程來起子進(jìn)程。使用for循環(huán)就可以了。   

 #如果獲得的總數(shù)小于或等于0,等待60秒,并退出
  if ($count <= 0) 
  {
    sleep(60);
    exit;
  }
  #如果大于1000,計(jì)算需要起的進(jìn)程數(shù)
  if ($count > 1000)
  {
    $cycleSize = ceil($count/1000);
  }
  else
  {
    $cycleSize = 1;
  }
  
  for ($i=0; $i<$cycleSize; $i++)
  {
    $pid  = pcntl_fork();
    if($pid == -1)
    {
      break;
    }
    else
    {
      if($pid)
      {
        #父進(jìn)程獲得子進(jìn)程的pid,存入數(shù)組
        $pidArr[] = $pid;
      }
      else
      {
        //開始發(fā)送,子進(jìn)程執(zhí)行完自己的任務(wù)后,退出。
          exit;
      }
    }
  }
  
  while(count($pidArr) > 0)
  {
    $myId  = pcntl_waitpid(-1, $status, WNOHANG);
    foreach($pidArr as $key => $pid)
    {
      if($myId == $pid) unset($pidArr[$key]);
    }
  }

    然后使用crontab,來使此PHP程序每隔一段時(shí)間自動(dòng)執(zhí)行。

    當(dāng)然,示例代碼比較簡單,具體還需要考慮怎么防止多個(gè)子進(jìn)程執(zhí)行到同一條數(shù)據(jù)或者當(dāng)前進(jìn)程處理數(shù)據(jù)未完成時(shí),crontab又開始執(zhí)行PHP文件啟用新的進(jìn)程等等。


PHP多進(jìn)程實(shí)現(xiàn)方式
下面來系統(tǒng)地整理一下PHP多進(jìn)程的實(shí)現(xiàn)方式:

1. 直接方式

pcntl_fork() 創(chuàng)建一個(gè)進(jìn)程,在父進(jìn)程返回值是子進(jìn)程的pid,在子進(jìn)程返回值是0,-1表示創(chuàng)建進(jìn)程失敗。跟C非常相似。

測試腳本 test.php
 

<?php
  // example of multiple processes
  date_default_timezone_set( 'Asia/Chongqing');
  echo "parent start, pid ", getmypid(), "\n" ;
  beep();
  for ($i=0; $i<3; ++$i){
     $pid = pcntl_fork();
      if ($pid == -1){
         die ("cannot fork" );
     } else if ($pid > 0){
         echo "parent continue \n";
         for ($k=0; $k<2; ++$k){
           beep();
        }
     } else if ($pid == 0){
         echo "child start, pid ", getmypid(), "\n" ;
         for ($j=0; $j<5; ++$j){
           beep();
        }
         exit ;
     }
  }
  // ***
  function beep(){
      echo getmypid(), "\t" , date( 'Y-m-d H:i:s', time()), "\n" ;
     sleep(1);
  }
?>

用命令行運(yùn)行

#php -f test.php

輸出結(jié)果

parent start, pid 1793
1793  2013-01-14 15:04:17
parent continue
1793  2013-01-14 15:04:18
child start, pid 1794
1794  2013-01-14 15:04:18
1794  2013-01-14 15:04:19
1793  2013-01-14 15:04:19
1794  2013-01-14 15:04:20
parent continue
1793  2013-01-14 15:04:20
child start, pid 1795
1795  2013-01-14 15:04:20
17931794        2013-01-14 15:04:212013-01-14 15:04:21

1795  2013-01-14 15:04:21
1794  2013-01-14 15:04:22
1795  2013-01-14 15:04:22
parent continue
1793  2013-01-14 15:04:22
child start, pid 1796
1796  2013-01-14 15:04:22
1793  2013-01-14 15:04:23
1796  2013-01-14 15:04:23
1795  2013-01-14 15:04:23
1795  2013-01-14 15:04:24
1796  2013-01-14 15:04:24
1796  2013-01-14 15:04:25
1796  2013-01-14 15:04:26

從中看到,創(chuàng)建了3個(gè)子進(jìn)程,和父進(jìn)程一起并行運(yùn)行。其中有一行格式跟其他有些不同,
17931794                2013-01-14 15:04:212013-01-14 15:04:21
因?yàn)閮蓚€(gè)進(jìn)程同時(shí)進(jìn)行寫操作,造成了沖突。


2. 阻塞方式

用直接方式,父進(jìn)程創(chuàng)建了子進(jìn)程后,并沒有等待子進(jìn)程結(jié)束,而是繼續(xù)運(yùn)行。似乎這里看不到有什么問題。如果php腳本并不是運(yùn)行完后自動(dòng)結(jié)束,而是常駐內(nèi)存的,就會(huì)造成子進(jìn)程無法回收的問題。也就是僵尸進(jìn)程??梢酝ㄟ^pcntl_wai()方法等待進(jìn)程結(jié)束,然后回收已經(jīng)結(jié)束的進(jìn)程。
將測試腳本改成:
 

$pid = pcntl_fork();
if ($pid == -1){
  ...
} else if ($pid > 0){
   echo "parent continue \n";
   pcntl_wait($status);
   for ($k=0; $k<2; ++$k){
     beep();
  }
} else if ($pid == 0){
   ...
}

用命令行運(yùn)行

#php -f test.php

輸出結(jié)果

parent start, pid 1807
1807  2013-01-14 15:20:05
parent continue
child start, pid 1808
1808  2013-01-14 15:20:06
1808  2013-01-14 15:20:07
1808  2013-01-14 15:20:08
1808  2013-01-14 15:20:09
1808  2013-01-14 15:20:10
1807  2013-01-14 15:20:11
1807  2013-01-14 15:20:12
parent continue
child start, pid 1809
1809  2013-01-14 15:20:13
1809  2013-01-14 15:20:14
1809  2013-01-14 15:20:15
1809  2013-01-14 15:20:16
1809  2013-01-14 15:20:17
1807  2013-01-14 15:20:18
1807  2013-01-14 15:20:19
child start, pid 1810
1810  2013-01-14 15:20:20
parent continue
1810  2013-01-14 15:20:21
1810  2013-01-14 15:20:22
1810  2013-01-14 15:20:23
1810  2013-01-14 15:20:24
1807  2013-01-14 15:20:25
1807  2013-01-14 15:20:26

父進(jìn)程在pcntl_wait()將自己阻塞,等待子進(jìn)程運(yùn)行完了才接著運(yùn)行。


3. 非阻塞方式

阻塞方式失去了多進(jìn)程的并行性。還有一種方法,既可以回收已經(jīng)結(jié)束的子進(jìn)程,又可以并行。這就是非阻塞的方式。
修改腳本:
 

<?php
  // example of multiple processes
  date_default_timezone_set( 'Asia/Chongqing');
  declare (ticks = 1);
  pcntl_signal(SIGCHLD, "garbage" );
  echo "parent start, pid ", getmypid(), "\n" ;
  beep();
  for ($i=0; $i<3; ++$i){
     $pid = pcntl_fork();
      if ($pid == -1){
         die ("cannot fork" );
     } else if ($pid > 0){
         echo "parent continue \n";
         for ($k=0; $k<2; ++$k){
           beep();
        }
     } else if ($pid == 0){
         echo "child start, pid ", getmypid(), "\n" ;
         for ($j=0; $j<5; ++$j){
           beep();
        }
         exit (0);
     }
  }
  // parent
  while (1){
      // do something else
     sleep(5);
  }
  // ***
  function garbage($signal){
      echo "signel $signal received\n" ;
      
      while (($pid = pcntl_waitpid(-1, $status, WNOHANG))> 0){
         echo "\t child end pid $pid , status $status\n" ;
     }
  }
  function beep(){
      echo getmypid(), "\t" , date( 'Y-m-d H:i:s', time()), "\n" ;
     sleep(1);
  }
?>

用命令行運(yùn)行

#php -f test.php &

輸出結(jié)果

parent start, pid 2066
2066  2013-01-14 16:45:34
parent continue
2066  2013-01-14 16:45:35
child start, pid 2067
2067  2013-01-14 16:45:35
20662067        2013-01-14 16:45:362013-01-14 16:45:36

2067  2013-01-14 16:45:37
parent continue
2066  2013-01-14 16:45:37
child start, pid 2068
2068  2013-01-14 16:45:37
2067  2013-01-14 16:45:38
2068  2013-01-14 16:45:38
2066  2013-01-14 16:45:38
parent continue
2066  2013-01-14 16:45:40
child start, pid 2069
2069  2067  2013-01-14 16:45:40
2013-01-14 16:45:40
2068  2013-01-14 16:45:40
2066  2013-01-14 16:45:41
2069  2013-01-14 16:45:41
2068  2013-01-14 16:45:41
signel 17 received
     child end pid 2067, status 0
2069  2013-01-14 16:45:42
2068  2013-01-14 16:45:42
2069  2013-01-14 16:45:43
signel 17 received
     child end pid 2068, status 0
2069  2013-01-14 16:45:44
signel 17 received
     child end pid 2069, status 0

多個(gè)進(jìn)程又并行運(yùn)行了,而且運(yùn)行大約10秒鐘之后,用 ps -ef | grep php 查看正在運(yùn)行的進(jìn)程,只有一個(gè)進(jìn)程
lqling    2066  1388  0 16:45 pts/1    00:00:00 php -f t5.php
是父進(jìn)程,子進(jìn)程被回收了。


子進(jìn)程退出狀態(tài)

pcntl_waitpid(-1, $status, WNOHANG) $status

 返回子進(jìn)程的結(jié)束狀態(tài)


windows下多線程

windows系統(tǒng)不支持pcntl函數(shù),幸好有curl_multi_exec()這個(gè)工具,利用內(nèi)部的多線程,訪問多個(gè)鏈接,每個(gè)鏈接可以作為一個(gè)任務(wù)。

編寫腳本 test1.php
 

<?php
  date_default_timezone_set( 'Asia/Chongqing');
  $tasks = array(
     'http://localhost/feedbowl/t2.php?job=task1',
     'http://localhost/feedbowl/t2.php?job=task2',
     'http://localhost/feedbowl/t2.php?job=task3'
  );
  $mh = curl_multi_init();
  foreach ($tasks as $i => $task){
     $ch[$i] = curl_init();
     curl_setopt($ch[$i], CURLOPT_URL, $task);
     curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1);
     curl_multi_add_handle($mh, $ch[$i]);
  }
  do {$mrc = curl_multi_exec($mh,$active); } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  while ($active && $mrc == CURLM_OK) {
     if (curl_multi_select($mh) != -1) {
      do {$mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM);
     }
  }
  // completed, checkout result
  foreach ($tasks as $j => $task){
     if (curl_error($ch[$j])){
       echo "task ${j} [$task ] error " , curl_error($ch[$j]), "\r\n" ;
     } else {
       echo "task ${j} [$task ] get: \r\n" , curl_multi_getcontent($ch[$j]), "\r\n" ;
     }
  }
?>

編寫腳本 test2.php
 

<?php
  date_default_timezone_set( 'Asia/Chongqing');
  echo "child start, pid ", getmypid(), "\r\n" ;
  for ($i=0; $i<5; ++$i){
     beep();
  }
  exit (0);
  // ***
  function beep(){
    echo getmypid(), "\t" , date('Y-m-d H:i:s' , time()), "\r\n";
    sleep(1);
  }
?>

用命令行運(yùn)行

#php -f test1.php &

輸出結(jié)果

task 0 [http://localhost/feedbowl/t2.php?job=task1] get:
child start, pid 5804
5804  2013-01-15 20:22:35
5804  2013-01-15 20:22:36
5804  2013-01-15 20:22:37
5804  2013-01-15 20:22:38
5804  2013-01-15 20:22:39

task 1 [http://localhost/feedbowl/t2.php?job=task2] get:
child start, pid 5804
5804  2013-01-15 20:22:35
5804  2013-01-15 20:22:36
5804  2013-01-15 20:22:37
5804  2013-01-15 20:22:38
5804  2013-01-15 20:22:39

task 2 [http://localhost/feedbowl/t2.php?job=task3] get:
child start, pid 5804
5804  2013-01-15 20:22:35
5804  2013-01-15 20:22:36
5804  2013-01-15 20:22:37
5804  2013-01-15 20:22:38
5804  2013-01-15 20:22:39

從打印的時(shí)間看到,多個(gè)任務(wù)幾乎是同時(shí)運(yùn)行的。

相關(guān)文章

  • php基于GD庫畫五星紅旗的方法

    php基于GD庫畫五星紅旗的方法

    這篇文章主要介紹了php基于GD庫畫五星紅旗的方法,涉及php操作GD庫及數(shù)組的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • php中iconv函數(shù)使用方法

    php中iconv函數(shù)使用方法

    最近在做一個(gè)程序,需要用到iconv函數(shù)把抓取來過的utf-8編碼的頁面轉(zhuǎn)成gb2312, 發(fā)現(xiàn)只有用iconv函數(shù)把抓取過來的數(shù)據(jù)一轉(zhuǎn)碼數(shù)據(jù)就會(huì)無緣無故的少一些。
    2008-05-05
  • PHP中一個(gè)有趣的preg_replace函數(shù)詳解

    PHP中一個(gè)有趣的preg_replace函數(shù)詳解

    這篇文章主要給大家介紹了關(guān)于PHP中一個(gè)有趣的preg_replace函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用php具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • php仿discuz分頁效果代碼

    php仿discuz分頁效果代碼

    模板discuz的分頁效果代碼,效果圖如下所示
    2008-10-10
  • PHP隨機(jī)生成唯一HASH值自定義函數(shù)

    PHP隨機(jī)生成唯一HASH值自定義函數(shù)

    這篇文章主要介紹了PHP隨機(jī)生成唯一HASH值自定義函數(shù),本文先是給出了需求,然后給出了實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2015-04-04
  • mac下Apache + MySql + PHP搭建網(wǎng)站開發(fā)環(huán)境

    mac下Apache + MySql + PHP搭建網(wǎng)站開發(fā)環(huán)境

    最近接了個(gè)小活,做一個(gè)使用PHP語言和MySql數(shù)據(jù)庫的動(dòng)態(tài)網(wǎng)站。之前做過類型的網(wǎng)站,是在windows系統(tǒng)下做的,開發(fā)環(huán)境使用的是 AppServ 的PHP開發(fā)套件?,F(xiàn)在有了我的大MAC,所以找了MAC系統(tǒng)下PHP環(huán)境的開發(fā)套件。
    2014-06-06
  • 對PHP PDO的一些認(rèn)識(shí)小結(jié)

    對PHP PDO的一些認(rèn)識(shí)小結(jié)

    這篇文章主要介紹了對PHP PDO的一些認(rèn)識(shí)小結(jié),本文講解了什么是PDO、啟用PDO的配置方法、PDO的預(yù)定義類、事務(wù)處理例子等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • PHP獲取毫秒級(jí)時(shí)間戳的方法

    PHP獲取毫秒級(jí)時(shí)間戳的方法

    這篇文章主要介紹了PHP獲取毫秒級(jí)時(shí)間戳的方法,涉及php針對microtime函數(shù)返回結(jié)果的處理技巧,非常簡單實(shí)用,需要的朋友可以參考下
    2015-04-04
  • php中rename函數(shù)用法分析

    php中rename函數(shù)用法分析

    這篇文章主要介紹了php中rename()函數(shù)用法,較為詳細(xì)的分析了rename()函數(shù)中參數(shù)的含義及具體的使用方法,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-11-11
  • PHP中使用asort進(jìn)行中文排序失效的問題處理

    PHP中使用asort進(jìn)行中文排序失效的問題處理

    asort() 函數(shù)對數(shù)組進(jìn)行排序并保持索引關(guān)系。主要用于對那些單元順序很重要的結(jié)合數(shù)組進(jìn)行排序??蛇x的第二個(gè)參數(shù)包含了附加的排序標(biāo)識(shí)。如果成功則返回 TRUE,否則返回 FALSE。
    2014-08-08

最新評論