深入解析PHP中的(偽)多線程與多進(jìn)程(2)_PHP教程
推薦:php 常用算法和時(shí)間復(fù)雜度本篇文章是對(duì)php中的常用算法以及時(shí)間復(fù)雜度進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下 按數(shù)量級(jí)遞增排列,常見的時(shí)間復(fù)雜度有:常數(shù)階O(1),對(duì)數(shù)階O(log2n),線性階O(n),線性對(duì)數(shù)階O(nlog2n),平方階O(n2),立方階O(n3) 復(fù)制代碼 代碼如下: //二分查找O(log2n) function erf
[文章二] 嘗試php命令行腳本多進(jìn)程并發(fā)執(zhí)行
除了fork, cli下的并發(fā)方式還有一種,看我的例子:
php不支持多線程,但是我們可以把問題轉(zhuǎn)換成“多進(jìn)程”來解決。由于php中的pcntl_fork只有unix平臺(tái)才可以使用,所以本文嘗試使用popen來替代。
下面是一個(gè)例子:
被并行調(diào)用的子程序代碼:
<?php
if($argc==1){
echo("argv\n");
}
$arg = $argv[1];
for($i=0; $i<10; $i++)
{
echo($i.".1.".time()." exec $arg \n");
if($arg=='php2'){
sleep(1);
echo($i.".2.".time()." exec $arg \n");
sleep(1);
}else{
sleep(1);
}
}
?>
主調(diào)用者程序,由他調(diào)用子進(jìn)程,同時(shí)并發(fā)的收集子程序的輸出
error_reporting(E_ALL);
$handle1 = popen('php sub.php php1', 'r');
$handle2 = popen('php sub.php php2', 'r');
$handle3 = popen('php sub.php php3', 'r');
echo "'$handle1'; " . gettype($handle1) . "\n";
echo "'$handle2'; " . gettype($handle2) . "\n";
echo "'$handle3'; " . gettype($handle3) . "\n";
//sleep(20);
while(!feof($handle1) || !feof($handle2) || !feof($handle3) )
{
$read = fgets($handle1);
echo $read;
$read = fgets($handle2);
echo $read;
$read = fgets($handle3);
echo $read;
}
pclose($handle1);
pclose($handle2);
pclose($handle3);
下面是我機(jī)器上的輸出:
C:\my_hunter>php exec.php
'Resource id #4'; resource
'Resource id #5'; resource
'Resource id #6'; resource
0.1.1147935331 exec php1
0.1.1147935331 exec php2
0.1.1147935331 exec php3
1.1.1147935332 exec php1
0.2.1147935332 exec php2
1.1.1147935332 exec php3
2.1.1147935333 exec php1
1.1.1147935333 exec php2
2.1.1147935333 exec php3
3.1.1147935334 exec php1
1.2.1147935334 exec php2
3.1.1147935334 exec php3
4.1.1147935335 exec php1
2.1.1147935335 exec php2
4.1.1147935335 exec php3
5.1.1147935336 exec php1
2.2.1147935336 exec php2
5.1.1147935336 exec php3
6.1.1147935337 exec php1
3.1.1147935337 exec php2
6.1.1147935337 exec php3
7.1.1147935338 exec php1
3.2.1147935338 exec php2
7.1.1147935338 exec php3
8.1.1147935339 exec php1
4.1.1147935339 exec php2
8.1.1147935339 exec php3
9.1.1147935340 exec php1
4.2.1147935340 exec php2
9.1.1147935340 exec php3
5.1.1147935341 exec php2
5.2.1147935342 exec php2
6.1.1147935343 exec php2
6.2.1147935344 exec php2
7.1.1147935345 exec php2
7.2.1147935346 exec php2
8.1.1147935347 exec php2
8.2.1147935348 exec php2
9.1.1147935349 exec php2
9.2.1147935350 exec php2
**總結(jié):**
**主程序循環(huán)等待子進(jìn)程, 通過fgets或fread 把子進(jìn)程的輸出獲取出來 , 從時(shí)間戳上看,的確實(shí)現(xiàn)了并發(fā)執(zhí)行。**
-----------------------------------------------
以后的改進(jìn):
* popen打開的句柄是單向的,如果需要向子進(jìn)程交互,可以使用proc_open
* 使用數(shù)組和子函數(shù)代替while(!feof($handle1)|| !feof($handle2) || !feof($handle3) )這種齷齪的寫法
* 用fread一次把子進(jìn)程已經(jīng)產(chǎn)生的輸出取完,而不是每次一行。
一個(gè)并發(fā)執(zhí)行shell任務(wù)的調(diào)度者,本程序讀取一個(gè)任務(wù)文件,把里面的每行命令并發(fā)執(zhí)行, 可以設(shè)置同時(shí)存在的子進(jìn)程數(shù)目:
/*
主任務(wù)管理器
并發(fā)的執(zhí)行子任務(wù)列表
*/
include("../common/conf.php");
include("../common/function.php");
//開啟的進(jìn)程數(shù)
$exec_number = 40 ;
/***** main ********/
if($argc==1){
echo("argv\n");
}
$taskfile = $argv[1];
//tasklist
$tasklist = file($taskfile);
$tasklist_len = count($tasklist);
$tasklist_pos = 0;
$handle_list = array();
while(1)
{
//子進(jìn)程列表有空閑,則填充補(bǔ)齊子進(jìn)程列表
if($exec_number > count($handle_list) &&
$tasklist_pos < $tasklist_len)
{
for($i=$tasklist_pos; $i<$tasklist_len; )
{
$command = $tasklist[$i] ;
$handle_list[] = popen($command , "r" );
tolog("begin task \t ".$tasklist[$i]);
$i++;
if($exec_number == count($handle_list)) break;
}
$tasklist_pos = $i;
}
//如果子進(jìn)程列表空,退出
if(0 == count($handle_list))
{
break;
}
//檢查子進(jìn)程列表的輸出,把停掉的子進(jìn)程關(guān)閉并記錄下來
$end_handle_keys = array();
foreach($handle_list as $key => $handle)
{
//$str = fgets($handle, 65536);
$str = fread($handle, 65536);
echo($str);
if(feof($handle))
{
$end_handle_keys[] = $key;
pclose($handle);
}
}
//踢出停掉的子進(jìn)程
foreach($end_handle_keys as $key)
{
unset($handle_list[$key]);
//var_dump($handle_list);
//exit;
}
}
tolog("\n\n*******************end**********************\n\n", "" , true);
附加一段Socket多進(jìn)程接收的代碼:
分享:解析PHP跳出循環(huán)的方法以及continue、break、exit的區(qū)別介紹PHP中的循環(huán)結(jié)構(gòu)大致有for循環(huán),while循環(huán),do{} while 循環(huán)以及foreach循環(huán)幾種,不管哪種循環(huán)中,在 PHP中跳出循環(huán)大致有這么幾種方式: 代碼: 復(fù)制代碼 代碼如下: ?php $i = 1; while (true) { // 這里看上去這個(gè)循環(huán)會(huì)一直執(zhí)行 if ($i==2) {// 2跳過不顯示 $i++;
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語言構(gòu)造器介紹
- php/js獲取客戶端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國語言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
- 相關(guān)鏈接:
- 教程說明:
PHP教程-深入解析PHP中的(偽)多線程與多進(jìn)程(2)
。