亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > PHP > 正文

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

2024-05-04 23:38:51
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了深入探究PHP的多進程編程方法,同時介紹了Windows系統下的多線程嘗試,是PHP并發實現方面的重要內容,需要的朋友可以參考下

子進程的創建

一般的子進程的寫法是:

 

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

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

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

 

 
  1. #如果獲得的總數小于或等于0,等待60秒,并退出 
  2. if ($count <= 0)  
  3. sleep(60); 
  4. exit
  5. #如果大于1000,計算需要起的進程數 
  6. if ($count > 1000) 
  7. $cycleSize = ceil($count/1000); 
  8. else 
  9. $cycleSize = 1; 
  10.  
  11. for ($i=0; $i<$cycleSize$i++) 
  12. $pid = pcntl_fork(); 
  13. if($pid == -1) 
  14. break
  15. else 
  16. if($pid
  17. #父進程獲得子進程的pid,存入數組 
  18. $pidArr[] = $pid
  19. else 
  20. //開始發送,子進程執行完自己的任務后,退出。 
  21. exit
  22.  
  23. while(count($pidArr) > 0) 
  24. $myId = pcntl_waitpid(-1, $status, WNOHANG); 
  25. foreach($pidArr as $key => $pid
  26. if($myId == $pid) unset($pidArr[$key]); 

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

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

PHP多進程實現方式

下面來系統地整理一下PHP多進程的實現方式:

1. 直接方式

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

測試腳本 test.php

 

 
  1. <?php 
  2. // example of multiple processes 
  3. date_default_timezone_set( 'Asia/Chongqing'); 
  4. echo "parent start, pid "getmypid(), "/n" ; 
  5. beep(); 
  6. for ($i=0; $i<3; ++$i){ 
  7. $pid = pcntl_fork(); 
  8. if ($pid == -1){ 
  9. die ("cannot fork" ); 
  10. else if ($pid > 0){ 
  11. echo "parent continue /n"
  12. for ($k=0; $k<2; ++$k){ 
  13. beep(); 
  14. else if ($pid == 0){ 
  15. echo "child start, pid "getmypid(), "/n" ; 
  16. for ($j=0; $j<5; ++$j){ 
  17. beep(); 
  18. exit ; 
  19. // *** 
  20. function beep(){ 
  21. echo getmypid(), "/t" , date'Y-m-d H:i:s', time()), "/n" ; 
  22. sleep(1); 
  23. ?> 

用命令行運行

 

 
  1. #php -f test.php 

輸出結果

 

 
  1. parent start, pid 1793 
  2. 1793 2013-01-14 15:04:17 
  3. parent continue 
  4. 1793 2013-01-14 15:04:18 
  5. child start, pid 1794 
  6. 1794 2013-01-14 15:04:18 
  7. 1794 2013-01-14 15:04:19 
  8. 1793 2013-01-14 15:04:19 
  9. 1794 2013-01-14 15:04:20 
  10. parent continue 
  11. 1793 2013-01-14 15:04:20 
  12. child start, pid 1795 
  13. 1795 2013-01-14 15:04:20 
  14. 17931794 2013-01-14 15:04:212013-01-14 15:04:21 
  15.  
  16. 1795 2013-01-14 15:04:21 
  17. 1794 2013-01-14 15:04:22 
  18. 1795 2013-01-14 15:04:22 
  19. parent continue 
  20. 1793 2013-01-14 15:04:22 
  21. child start, pid 1796 
  22. 1796 2013-01-14 15:04:22 
  23. 1793 2013-01-14 15:04:23 
  24. 1796 2013-01-14 15:04:23 
  25. 1795 2013-01-14 15:04:23 
  26. 1795 2013-01-14 15:04:24 
  27. 1796 2013-01-14 15:04:24 
  28. 1796 2013-01-14 15:04:25 
  29. 1796 2013-01-14 15:04:26 

從中看到,創建了3個子進程,和父進程一起并行運行。其中有一行格式跟其他有些不同,

17931794 2013-01-14 15:04:212013-01-14 15:04:21

因為兩個進程同時進行寫操作,造成了沖突。

2. 阻塞方式

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

將測試腳本改成:

 

 
  1. $pid = pcntl_fork(); 
  2. if ($pid == -1){ 
  3. ... 
  4. else if ($pid > 0){ 
  5. echo "parent continue /n"
  6. pcntl_wait($status); 
  7. for ($k=0; $k<2; ++$k){ 
  8. beep(); 
  9. else if ($pid == 0){ 
  10. ... 

用命令行運行

 

 
  1. #php -f test.php 

輸出結果

 

 
  1. parent start, pid 1807 
  2. 1807 2013-01-14 15:20:05 
  3. parent continue 
  4. child start, pid 1808 
  5. 1808 2013-01-14 15:20:06 
  6. 1808 2013-01-14 15:20:07 
  7. 1808 2013-01-14 15:20:08 
  8. 1808 2013-01-14 15:20:09 
  9. 1808 2013-01-14 15:20:10 
  10. 1807 2013-01-14 15:20:11 
  11. 1807 2013-01-14 15:20:12 
  12. parent continue 
  13. child start, pid 1809 
  14. 1809 2013-01-14 15:20:13 
  15. 1809 2013-01-14 15:20:14 
  16. 1809 2013-01-14 15:20:15 
  17. 1809 2013-01-14 15:20:16 
  18. 1809 2013-01-14 15:20:17 
  19. 1807 2013-01-14 15:20:18 
  20. 1807 2013-01-14 15:20:19 
  21. child start, pid 1810 
  22. 1810 2013-01-14 15:20:20 
  23. parent continue 
  24. 1810 2013-01-14 15:20:21 
  25. 1810 2013-01-14 15:20:22 
  26. 1810 2013-01-14 15:20:23 
  27. 1810 2013-01-14 15:20:24 
  28. 1807 2013-01-14 15:20:25 
  29. 1807 2013-01-14 15:20:26 

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

3. 非阻塞方式

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

修改腳本:

 

 
  1. <?php 
  2. // example of multiple processes 
  3. date_default_timezone_set( 'Asia/Chongqing'); 
  4. declare (ticks = 1); 
  5. pcntl_signal(SIGCHLD, "garbage" ); 
  6. echo "parent start, pid ", getmypid(), "/n" ; 
  7. beep(); 
  8. for ($i=0; $i<3; ++$i){ 
  9. $pid = pcntl_fork(); 
  10. if ($pid == -1){ 
  11. die ("cannot fork" ); 
  12. else if ($pid > 0){ 
  13. echo "parent continue /n"
  14. for ($k=0; $k<2; ++$k){ 
  15. beep(); 
  16. else if ($pid == 0){ 
  17. echo "child start, pid ", getmypid(), "/n" ; 
  18. for ($j=0; $j<5; ++$j){ 
  19. beep(); 
  20. exit (0); 
  21. // parent 
  22. while (1){ 
  23. // do something else 
  24. sleep(5); 
  25. // *** 
  26. function garbage($signal){ 
  27. echo "signel $signal received/n" ; 
  28.  
  29. while (($pid = pcntl_waitpid(-1, $status, WNOHANG))> 0){ 
  30. echo "/t child end pid $pid , status $status/n" ; 
  31. function beep(){ 
  32. echo getmypid(), "/t" , date( 'Y-m-d H:i:s', time()), "/n" ; 
  33. sleep(1); 
  34. ?> 

用命令行運行

 

 
  1. #php -f test.php & 

輸出結果

 

 
  1. parent start, pid 2066 
  2. 2066 2013-01-14 16:45:34 
  3. parent continue 
  4. 2066 2013-01-14 16:45:35 
  5. child start, pid 2067 
  6. 2067 2013-01-14 16:45:35 
  7. 20662067 2013-01-14 16:45:362013-01-14 16:45:36 
  8.  
  9. 2067 2013-01-14 16:45:37 
  10. parent continue 
  11. 2066 2013-01-14 16:45:37 
  12. child start, pid 2068 
  13. 2068 2013-01-14 16:45:37 
  14. 2067 2013-01-14 16:45:38 
  15. 2068 2013-01-14 16:45:38 
  16. 2066 2013-01-14 16:45:38 
  17. parent continue 
  18. 2066 2013-01-14 16:45:40 
  19. child start, pid 2069 
  20. 2069 2067 2013-01-14 16:45:40 
  21. 2013-01-14 16:45:40 
  22. 2068 2013-01-14 16:45:40 
  23. 2066 2013-01-14 16:45:41 
  24. 2069 2013-01-14 16:45:41 
  25. 2068 2013-01-14 16:45:41 
  26. signel 17 received 
  27. child end pid 2067, status 0 
  28. 2069 2013-01-14 16:45:42 
  29. 2068 2013-01-14 16:45:42 
  30. 2069 2013-01-14 16:45:43 
  31. signel 17 received 
  32. child end pid 2068, status 0 
  33. 2069 2013-01-14 16:45:44 
  34. signel 17 received 
  35. 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

是父進程,子進程被回收了。

子進程退出狀態

 

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

返回子進程的結束狀態

windows下多線程

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

編寫腳本 test1.php

 

 
  1. <?php 
  2. date_default_timezone_set( 'Asia/Chongqing'); 
  3. $tasks = array( 
  4. 'http://localhost/feedbowl/t2.php?job=task1'
  5. 'http://localhost/feedbowl/t2.php?job=task2'
  6. 'http://localhost/feedbowl/t2.php?job=task3' 
  7. ); 
  8. $mh = curl_multi_init(); 
  9. foreach ($tasks as $i => $task){ 
  10. $ch[$i] = curl_init(); 
  11. curl_setopt($ch[$i], CURLOPT_URL, $task); 
  12. curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1); 
  13. curl_multi_add_handle($mh, $ch[$i]); 
  14. do {$mrc = curl_multi_exec($mh,$active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); 
  15. while ($active && $mrc == CURLM_OK) { 
  16. if (curl_multi_select($mh) != -1) { 
  17. do {$mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); 
  18. // completed, checkout result 
  19. foreach ($tasks as $j => $task){ 
  20. if (curl_error($ch[$j])){ 
  21. echo "task ${j} [$task ] error " , curl_error($ch[$j]), "/r/n" ; 
  22. else { 
  23. echo "task ${j} [$task ] get: /r/n" , curl_multi_getcontent($ch[$j]), "/r/n" ; 
  24. ?> 

編寫腳本 test2.php

 

 
  1. <?php 
  2. date_default_timezone_set( 'Asia/Chongqing'); 
  3. echo "child start, pid ", getmypid(), "/r/n" ; 
  4. for ($i=0; $i<5; ++$i){ 
  5. beep(); 
  6. exit (0); 
  7. // *** 
  8. function beep(){ 
  9. echo getmypid(), "/t" , date('Y-m-d H:i:s' , time()), "/r/n"
  10. sleep(1); 
  11. ?> 

用命令行運行

 

 
  1. #php -f test1.php & 

輸出結果

 

 
  1. task 0 [http://localhost/feedbowl/t2.php?job=task1] get: 
  2. child start, pid 5804 
  3. 5804 2013-01-15 20:22:35 
  4. 5804 2013-01-15 20:22:36 
  5. 5804 2013-01-15 20:22:37 
  6. 5804 2013-01-15 20:22:38 
  7. 5804 2013-01-15 20:22:39 
  8.  
  9. task 1 [http://localhost/feedbowl/t2.php?job=task2] get: 
  10. child start, pid 5804 
  11. 5804 2013-01-15 20:22:35 
  12. 5804 2013-01-15 20:22:36 
  13. 5804 2013-01-15 20:22:37 
  14. 5804 2013-01-15 20:22:38 
  15. 5804 2013-01-15 20:22:39 
  16.  
  17. task 2 [http://localhost/feedbowl/t2.php?job=task3] get: 
  18. child start, pid 5804 
  19. 5804 2013-01-15 20:22:35 
  20. 5804 2013-01-15 20:22:36 
  21. 5804 2013-01-15 20:22:37 
  22. 5804 2013-01-15 20:22:38 
  23. 5804 2013-01-15 20:22:39 

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲另类欧美自拍| 国产精品一区二区三区在线播放| 亚洲丝袜在线视频| 国产日产欧美精品| 久久天天躁狠狠躁老女人| 日韩高清不卡av| 亚洲精品久久久久久久久久久| 亚洲成人激情视频| 国产精品户外野外| 欧美一区二区三区图| 亚洲一区二区少妇| 一区二区三区视频在线| 久久精品电影网| 日本欧美黄网站| 三级精品视频久久久久| 亚洲国产成人久久| 亚洲国产精品久久久久秋霞蜜臀| 亚洲精品按摩视频| 欧美激情2020午夜免费观看| 国产精品成人久久久久| 成人av色在线观看| 久久久久久久久国产精品| 亚洲在线观看视频网站| 日韩av大片免费看| 日本精品久久久久久久| 国产a∨精品一区二区三区不卡| 久久久久久久久久国产精品| 欧美老女人性视频| 动漫精品一区二区| 在线观看亚洲区| 欧美一级视频免费在线观看| 欧美激情久久久| 亚洲天堂av在线免费观看| 亚洲人成电影网站色xx| 欧美亚洲视频在线看网址| 久热在线中文字幕色999舞| 中文字幕精品—区二区| 国产成人精品a视频一区www| 亚洲free性xxxx护士白浆| 国产精品精品久久久| 一本大道久久加勒比香蕉| 亚洲欧美在线免费观看| 超碰97人人做人人爱少妇| 亚洲va久久久噜噜噜久久天堂| 亚洲一区二区三| 亚洲无限乱码一二三四麻| 亚洲精品在线观看www| 精品亚洲aⅴ在线观看| 黑人巨大精品欧美一区二区一视频| 日韩欧美亚洲成人| 久久精品亚洲精品| 中文字幕国产亚洲| 精品久久久999| 欧美视频一区二区三区…| 国产精品午夜一区二区欲梦| 精品亚洲va在线va天堂资源站| 欧美黑人xxxⅹ高潮交| 夜夜嗨av一区二区三区免费区| 2019国产精品自在线拍国产不卡| 国产mv免费观看入口亚洲| 精品国产区一区二区三区在线观看| 国产一区二区在线播放| 岛国视频午夜一区免费在线观看| 亚洲片在线观看| 国产成人综合精品在线| 亚洲美女性生活视频| 亚洲一区二区三区乱码aⅴ蜜桃女| 亚洲精品99久久久久| 亚洲xxxx3d| 亚洲另类激情图| 欧洲美女7788成人免费视频| 日韩视频―中文字幕| 亚洲视频999| 91久久精品视频| 国产精品久久久久久超碰| 国产精品永久免费观看| 色妞久久福利网| 亚洲精品狠狠操| 成人午夜小视频| 欧亚精品在线观看| 久久久精品国产亚洲| 精品五月天久久| 国产亚洲欧美日韩美女| 国产视频在线观看一区二区| 成人激情av在线| 亚洲成人在线视频播放| 国产做受高潮69| 久久久久www| 国产精品嫩草视频| 国产欧美最新羞羞视频在线观看| 亚洲欧美激情四射在线日| 色婷婷av一区二区三区久久| 亚洲高清久久网| 久久91亚洲精品中文字幕奶水| 久久躁狠狠躁夜夜爽| 久久艹在线视频| 97在线看免费观看视频在线观看| 久久久久久久成人| 日韩免费av片在线观看| 日韩一中文字幕| 亚洲天堂一区二区三区| 一本一道久久a久久精品逆3p| 亚洲一区二区精品| 欧美在线观看视频| 欧美一区二区三区……| 一本色道久久综合亚洲精品小说| 国产精品自产拍在线观| 久久久久久亚洲精品| 国产精品电影久久久久电影网| 亚洲国产另类久久精品| 日本久久久久久久久久久| 亚洲精品国产拍免费91在线| 欧美成人免费大片| 日韩免费不卡av| 2019最新中文字幕| 欧美成人免费在线视频| 国产一区二区三区在线观看网站| 一本色道久久综合亚洲精品小说| 国产精品视频区1| 在线视频欧美性高潮| 久久97久久97精品免视看| 91精品久久久久久久久久久久久久| 韩国美女主播一区| 国产成人精品国内自产拍免费看| 国产在线观看一区二区三区| 欧美一区第一页| 亚洲字幕一区二区| 国产成人在线一区二区| 少妇高潮久久久久久潘金莲| 97碰在线观看| 成人午夜黄色影院| 亚洲精品乱码久久久久久按摩观| 欧美亚洲成人网| 国产精品久久视频| 国产日韩欧美自拍| 成人激情综合网| 日韩国产精品视频| 国产婷婷97碰碰久久人人蜜臀| 国产成人小视频在线观看| 亚洲色图50p| 日韩日本欧美亚洲| 国产亚洲视频在线观看| 欧美成在线视频| 久久香蕉国产线看观看网| 欧美黑人巨大精品一区二区| 中文字幕久精品免费视频| 亚洲bt欧美bt日本bt| 久久人人爽人人爽人人片av高清| 亚洲伊人久久大香线蕉av| 欧美日韩国产精品一区二区不卡中文| 久久久伊人欧美| 亚洲最大福利网| 日韩中文字幕在线观看| 久久青草福利网站| 久久免费少妇高潮久久精品99| 久久久久久av| 欧美激情第一页xxx| 亚洲精品国产成人| 欧美成人免费在线观看| 亚洲国产福利在线| 成人午夜在线影院| 欧美激情区在线播放| 国产女精品视频网站免费| 国产精品成av人在线视午夜片|