亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入探究PHP的多進程編程方法

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

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

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

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

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

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

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

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


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

1. 直接方式

pcntl_fork() 創(chuàng)建一個進程,在父進程返回值是子進程的pid,在子進程返回值是0,-1表示創(chuàng)建進程失敗。跟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);
  }
?>

用命令行運行

#php -f test.php

輸出結果

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個子進程,和父進程一起并行運行。其中有一行格式跟其他有些不同,
17931794                2013-01-14 15:04:212013-01-14 15:04:21
因為兩個進程同時進行寫操作,造成了沖突。


2. 阻塞方式

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

$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){
   ...
}

用命令行運行

#php -f test.php

輸出結果

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

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


3. 非阻塞方式

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

<?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);
  }
?>

用命令行運行

#php -f test.php &

輸出結果

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

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


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

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

 返回子進程的結束狀態(tài)


windows下多線程

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

編寫腳本 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);
  }
?>

用命令行運行

#php -f test1.php &

輸出結果

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

從打印的時間看到,多個任務幾乎是同時運行的。

相關文章

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

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

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

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

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

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

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

    php仿discuz分頁效果代碼

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

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

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

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

    最近接了個小活,做一個使用PHP語言和MySql數(shù)據(jù)庫的動態(tài)網站。之前做過類型的網站,是在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的一些認識小結

    對PHP PDO的一些認識小結

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

    PHP獲取毫秒級時間戳的方法

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

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

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

    PHP中使用asort進行中文排序失效的問題處理

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

最新評論