標題: [學(xué)習] PHP中的(偽)多線(xiàn)程與多進(jìn)程
[打印本頁(yè)]
作者: HonestQiao
時(shí)間: 2005-12-2 15:32
標題: [學(xué)習] PHP中的(偽)多線(xiàn)程與多進(jìn)程
[學(xué)習] PHP中的(偽)多線(xiàn)程與多進(jìn)程
已經(jīng)因為沒(méi)怎么需要,所以沒(méi)有查這個(gè)的資料。最近有一個(gè)項目卻是需要這樣子的功能。
查看了PHP的手冊和他人的例子,了解到基本的兩種方法:
(偽)多線(xiàn)程:借助外力
利用WEB服務(wù)器本身的多線(xiàn)程來(lái)處理,從WEB服務(wù)器多次調用我們需要實(shí)現多線(xiàn)程的程序。
以下轉載自:http://www.laikan8.com/21/118472.html
QUOTE:
我們知道PHP本身是不支持多線(xiàn)程的, 但是我們的WEB服務(wù)器是支持多線(xiàn)程的.
也就是說(shuō)可以同時(shí)讓多人一起訪(fǎng)問(wèn). 這也是我在PHP中實(shí)現多線(xiàn)程的基礎.
假設我們現在運行的是a.php這個(gè)文件. 但是我在程序中又請求WEB服務(wù)器運行另一個(gè)b.php
那么這兩個(gè)文件將是同時(shí)執行的.
(PS: 一個(gè)鏈接請求發(fā)送之后, WEB服務(wù)器就會(huì )執行它, 而不管客戶(hù)端是否已經(jīng)退出)
有些時(shí)候, 我們想運行的不是另一個(gè)文件, 而是本文件中的一部分代碼.該怎么辦呢?
其實(shí)可是通過(guò)參數來(lái)控制a.php來(lái)運行哪一段程序.
下面看一個(gè)例子:
//a.php
PHP代碼:--------------------------------------------------------------------------------
<?php
function runThread()
{
$fp = fsockopen(‘localhost‘, 80, $errno, $errmsg);
fputs($fp, "GET /a.php?act=brnrn"); //這里的第二個(gè)參數是HTTP協(xié)議中規定的請求頭
//不明白的請看RFC中的定義
fclose($fp);
}
function a()
{
$fp = fopen(‘result_a.log‘, ‘w‘);
fputs($fp, ‘Set in ‘ . Date(‘h:i:s‘, time()) . (double)microtime() . "rn");
fclose($fp);
}
function b()
{
$fp = fopen(‘result_b.log‘, ‘w‘);
fputs($fp, ‘Set in ‘ . Date(‘h:i:s‘, time()) . (double)microtime() . "rn");
fclose($fp);
}
if(!isset($_GET[‘a(chǎn)ct‘])) $_GET[‘a(chǎn)ct‘] = ‘a(chǎn)‘;
if($_GET[‘a(chǎn)ct‘] == ‘a(chǎn)‘)
{
runThread();
a();
}
else if($_GET[‘a(chǎn)ct‘] == ‘b‘) b();
?>
--------------------------------------------------------------------------------
打開(kāi)result_a.log 和 result_b.log 比較一下兩個(gè)文件的中訪(fǎng)問(wèn)的時(shí)間. 大家會(huì )發(fā)現, 這兩個(gè)的確是在不同線(xiàn)程中運行的.
有些時(shí)間完全一樣.
上面只是一個(gè)簡(jiǎn)單的例子, 大家可以改進(jìn)成其它形式.
既然PHP中也能多線(xiàn)程了, 那么問(wèn)題也來(lái)了, 那就是同步的問(wèn)題. 我們知道 PHP本身是不支持多線(xiàn)程的. 所以更不會(huì )有什么像
Java 中synchronize的方法了. 那我們該如何做呢.
1. 盡量不訪(fǎng)問(wèn)同一個(gè)資源. 以避免沖突. 但是可以同時(shí)像數據庫操作. 因為數據庫是支持并發(fā)操作的. 所以在多線(xiàn)程的PHP中
不要向同一個(gè)文件中寫(xiě)入數據. 如果必須要寫(xiě)的話(huà), 用別的方法進(jìn)行同步.. 如調用 flock對文件進(jìn)行加鎖等. 或建立臨時(shí)文件
并在另外的線(xiàn)程中等待這個(gè)文件的消失 while(file_exits(‘xxx‘)); 這樣就等于這個(gè)臨時(shí)文件存在時(shí), 表示其實(shí)線(xiàn)程正在操作
如果沒(méi)有了這個(gè)文件, 說(shuō)明其它線(xiàn)程已經(jīng)釋放了這個(gè).
2. 盡量不要從runThread在執行fputs后取這個(gè)socket中讀取數據. 因為要實(shí)現多線(xiàn)程, 需要的用非阻塞模式. 即在像fgets這
樣的函數時(shí)立即返回.. 所以讀寫(xiě)數據就會(huì )出問(wèn)題. 如果使用阻塞模式的話(huà), 程序就不算是多線(xiàn)程了. 他要等上面的返回才執行
下面的程序. 所以如果需要交換數據最后利用外面文件或數據中完成. 實(shí)在想要的話(huà)就用socket_set_nonblock($fp) 來(lái)實(shí)現.
說(shuō)了這么多, 倒底這個(gè)有沒(méi)有實(shí)際的意義呢? 在什么時(shí)候需要這種用這種方法呢 ?
答案是肯定的. 大家知道. 在一個(gè)不斷讀取網(wǎng)絡(luò )資源的應用中, 網(wǎng)絡(luò )的速度是瓶頸. 如果采多這種形式就可以同時(shí)以多個(gè)線(xiàn)程對
不同的頁(yè)面進(jìn)行讀取.
本人做的一個(gè)能從8848、soaso這些商城網(wǎng)站搜索信息的程序。還有一個(gè)從阿里巴巴網(wǎng)站上讀取商業(yè)信息和公司目錄的程序也用到
了此技術(shù)。 因為這兩個(gè)程序都是要不斷的鏈接它們的服務(wù)器讀取信息并保存到數據庫。 利用此技術(shù)正好消除了在等待響應時(shí)的瓶
頸。
多進(jìn)程:使用PHP的Process Control Functions(PCNTL/線(xiàn)程控制函數)
函數參考可見(jiàn):http://www.php.net/manual/zh/ref.pcntl.php
只能用在Unix Like OS,Windows不可用。
編譯php的時(shí)候,需要加上--enable-pcntl,且推薦僅僅在CLI模式運行,不要在WEB服務(wù)器環(huán)境運行。
以下為簡(jiǎn)短的測試代碼:
<?php
declare(ticks=1);
$bWaitFlag = FALSE; /// 是否等待進(jìn)程結束
$intNum = 10; /// 進(jìn)程總數
$pids = array(); /// 進(jìn)程PID數組
echo ("Start\n");
for($i = 0; $i < $intNum; $i++) {
$pids[$i] = pcntl_fork();/// 產(chǎn)生子進(jìn)程,而且從當前行之下開(kāi)試運行代碼,而且不繼承父進(jìn)程的數據信息
if(!$pids[$i]) {
// 子進(jìn)程進(jìn)程代碼段_Start
$str="";
sleep(5+$i);
for ($j=0;$j<$i;$j++) {$str.="*";}
echo "$i -> " . time() . " $str \n";
exit();
// 子進(jìn)程進(jìn)程代碼段_End
}
}
if ($bWaitFlag)
{
for($i = 0; $i < $intNum; $i++) {
pcntl_waitpid($pids[$i], $status, WUNTRACED);
echo "wait $i -> " . time() . "\n";
}
}
echo ("End\n");
?>
運行結果如下:
[qiao@oicq qiao]$ php test.php
Start
End
[qiao@oicq qiao]$ ps -aux | grep "php"
qiao 32275 0.0 0.5 49668 6148 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32276 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32277 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32278 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32279 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32280 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32281 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32282 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32283 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32284 0.0 0.5 49668 6152 pts/1 S 14:03 0:00 /usr/local/php4/b
qiao 32286 0.0 0.0 1620 600 pts/1 S 14:03 0:00 grep php
[qiao@oicq qiao]$ 0 -> 1133503401
1 -> 1133503402 *
2 -> 1133503403 **
3 -> 1133503404 ***
4 -> 1133503405 ****
5 -> 1133503406 *****
6 -> 1133503407 ******
7 -> 1133503408 *******
8 -> 1133503409 ********
9 -> 1133503410 *********
[qiao@oicq qiao]$
如果$bWaitFlag=TURE,則結果如下:
[qiao@oicq qiao]$ php test.php
Start
0 -> 1133503602
wait 0 -> 1133503602
1 -> 1133503603 *
wait 1 -> 1133503603
2 -> 1133503604 **
wait 2 -> 1133503604
3 -> 1133503605 ***
wait 3 -> 1133503605
4 -> 1133503606 ****
wait 4 -> 1133503606
5 -> 1133503607 *****
wait 5 -> 1133503607
6 -> 1133503608 ******
wait 6 -> 1133503608
7 -> 1133503609 *******
wait 7 -> 1133503609
8 -> 1133503610 ********
wait 8 -> 1133503610
9 -> 1133503611 *********
wait 9 -> 1133503611
End
[qiao@oicq qiao]$
從多進(jìn)程的例子可以看出,使用pcntl_fork()之后,將生成一個(gè)子進(jìn)程,而且子進(jìn)程運行的代碼,從pcntl_fork()之后的代碼開(kāi)始,而子進(jìn)程不繼承父進(jìn)程的數據信息(實(shí)際上是把父進(jìn)程的數據做了一個(gè)全新的拷貝),因而使用if(!$pids[$i]) 來(lái)控制子進(jìn)程實(shí)際運行的代碼段。
更詳細的研究出于時(shí)間關(guān)系,暫時(shí)沒(méi)有進(jìn)行,你可以參考我給出的手冊的鏈接。
[
本帖最后由 HonestQiao 于 2005-12-2 22:02 編輯 ]
作者: hitty
時(shí)間: 2005-12-2 15:41
好像在 phpx 上看到過(guò)
例二是不是可以用來(lái)暴力破解
[
本帖最后由 hitty 于 2005-12-2 15:46 編輯 ]
作者: xuzuning
時(shí)間: 2005-12-2 15:59
看不出有什么實(shí)際意義
如果當前程序不需要“進(jìn)程”的結果,那么要打開(kāi)那個(gè)“進(jìn)程”干什么?
如果當前程序需要使用“進(jìn)程”的結果,那么你終歸是要等待“進(jìn)程”的結束,那么多不多又有什么區別呢?
作者: HonestQiao
時(shí)間: 2005-12-2 16:32
QUOTE:
原帖由 xuzuning 于 2005-12-2 15:59 發(fā)表
看不出有什么實(shí)際意義
如果當前程序不需要“進(jìn)程”的結果,那么要打開(kāi)那個(gè)“進(jìn)程”干什么?
如果當前程序需要使用“進(jìn)程”的結果,那么你終歸是要等待“進(jìn)程”的結束,那么多不多又有什么區別呢?
做類(lèi)似頁(yè)面抓取的工作可能需要,不然一次一個(gè)頁(yè)面抓取浪費帶寬。
再如做本地的文件轉換,例如有一批文件需要轉換。
其實(shí)進(jìn)程之間可以使用很多方法通信。
當然可以手動(dòng)啟動(dòng)很多進(jìn)程,但是畢竟它提供了這個(gè)功能,你可以看pcntl的手冊,它可以對子進(jìn)程進(jìn)行控制,例如他結束你可以知道,他超時(shí)你可以處理。
作者: xuzuning
時(shí)間: 2005-12-2 16:47
沒(méi)有看清楚!
編譯php的時(shí)候,需要加上--enable-pcntl,且推薦僅僅在CLI模式運行,不要在WEB服務(wù)器環(huán)境運行。
呵呵!
用c或shell要好多了吧?
作者: HonestQiao
時(shí)間: 2005-12-2 16:49
QUOTE:
原帖由 xuzuning 于 2005-12-2 16:47 發(fā)表
沒(méi)有看清楚!
編譯php的時(shí)候,需要加上--enable-pcntl,且推薦僅僅在CLI模式運行,不要在WEB服務(wù)器環(huán)境運行。
呵呵!
用c或shell要好多了吧?
用c當然無(wú)可厚非,不過(guò)門(mén)檻比php高多了。
但是用shell可能不是很多人可以接受。
作者: wobushiwo
時(shí)間: 2005-12-2 17:05
我也是借助外力,是OS本身的多進(jìn)程
不覺(jué)得這樣控制有什么優(yōu)勢,甚至會(huì )加大復雜程度
作者: hightman
時(shí)間: 2005-12-2 18:29
QUOTE:
原帖由 HonestQiao 于 2005-12-2 15:32 發(fā)表
從多進(jìn)程的例子可以看出,使用pcntl_fork()之后,將生成一個(gè)子進(jìn)程,而且子進(jìn)程運行的代碼,從pcntl_fork()之后的代碼開(kāi)始,而子進(jìn)程不繼承父進(jìn)程的數據信息,因而使用if(!$pids[$i]) 來(lái)控制子進(jìn)程實(shí)際運行的代碼段。
這里表述不當, 子進(jìn)程繼承了父進(jìn)程的很多數據信息.
而 $pids[$i] 是 pcntl_fork() 的返回值, 進(jìn)程創(chuàng )建后子進(jìn)程返回 0 父進(jìn)程返回子進(jìn)程. 所以用 fork() 的返回值區別子進(jìn)程或者父進(jìn)程.
由于進(jìn)程/線(xiàn)程都是系統的調度單位, 參與系統資源競爭, 所以適當情況下多進(jìn)程/線(xiàn)程是十分必要的, 而不是像某些回貼說(shuō)的增加復雜度.
有些情況不是借助外力可以創(chuàng )建進(jìn)程就行的, 可能需要從父進(jìn)程中讀取一些信息呢.
作者: Haohappy
時(shí)間: 2005-12-2 19:38
多線(xiàn)程還是很好用的,我做過(guò)的項目中就有用到,也是用于搜索,抓取WEB頁(yè)面。
如果是在Unix下,沒(méi)有必要采用
$fp = fsockopen(‘localhost‘, 80, $errno, $errmsg);
fputs($fp, "GET /a.php?act=brnrn");
直接用exec("php a.php args")這樣更方便。
作者: wobushiwo
時(shí)間: 2005-12-2 20:32
我的方法大概像 Haohappy
php本身處理多線(xiàn)程/進(jìn)程就不好,我認為沒(méi)必要搞一個(gè) 偽 多線(xiàn)程與多進(jìn)程,增加編寫(xiě)php編寫(xiě)的難度
有必要嗎?假如本身就是假的,是為了一種實(shí)現方式,那另一種辦法也能實(shí)現,而且又不用增加任何代碼等
為啥要像LZ那樣去寫(xiě)?
請注意哦:是LZ的實(shí)現方式我覺(jué)得沒(méi)必要,不是說(shuō)多線(xiàn)程/進(jìn)程不好,偶寫(xiě)的程序中多線(xiàn)程幫了很大忙
作者: hightman
時(shí)間: 2005-12-2 20:35
可是 exec() 可以說(shuō)是阻塞式的吧, 也就是說(shuō) exec() 要等它執行完才能執行后面的代碼
這樣就不符合要求了
作者: wobushiwo
時(shí)間: 2005-12-2 20:37
php fork出來(lái)的子進(jìn)程有那么特殊嗎?
一般來(lái)說(shuō)子會(huì )繼承父的信息的
LZ的說(shuō)明不繼承,我估計是建立在他的上下文中,也就是局限在那代碼的那個(gè)判斷中的意思吧?
作者: wobushiwo
時(shí)間: 2005-12-2 20:38
不好意思,是 + &
作者: wobushiwo
時(shí)間: 2005-12-2 20:39
假如不局限在一種語(yǔ)言或環(huán)境中,我常是多語(yǔ)言混編
假如可以的話(huà),我依靠OS,或者加上其他語(yǔ)言,而不會(huì )像LZ只用PHP去實(shí)現
MAYBE 我的 PHP太爛了
作者: HonestQiao
時(shí)間: 2005-12-2 22:03
QUOTE:
原帖由 wobushiwo 于 2005-12-2 20:37 發(fā)表
php fork出來(lái)的子進(jìn)程有那么特殊嗎?
一般來(lái)說(shuō)子會(huì )繼承父的信息的
LZ的說(shuō)明不繼承,我估計是建立在他的上下文中,也就是局限在那代碼的那個(gè)判斷中的意思吧?
可以有類(lèi)似的意思。
他是做了一個(gè)全新的拷貝,將不和原來(lái)的再發(fā)生關(guān)系。
作者: HonestQiao
時(shí)間: 2005-12-2 22:04
QUOTE:
原帖由 wobushiwo 于 2005-12-2 20:39 發(fā)表
假如不局限在一種語(yǔ)言或環(huán)境中,我常是多語(yǔ)言混編
假如可以的話(huà),我依靠OS,或者加上其他語(yǔ)言,而不會(huì )像LZ只用PHP去實(shí)現
MAYBE 我的 PHP太爛了
這個(gè),呵呵,僅僅是說(shuō)在PHP之中的。
用其他的,C++作多線(xiàn)程無(wú)疑比這個(gè)好多了。
但是有些時(shí)候可能并不需要C++來(lái)參與。
作者: diychen
時(shí)間: 2005-12-4 13:52
樓上你的方式是什么呢?
作者: Haohappy
時(shí)間: 2005-12-5 16:27
QUOTE:
原帖由 hightman 于 2005-12-2 20:35 發(fā)表
可是 exec() 可以說(shuō)是阻塞式的吧, 也就是說(shuō) exec() 要等它執行完才能執行后面的代碼
這樣就不符合要求了
這里有一個(gè)技巧哦,推薦給這里的朋友們:
如果你執行的是
php -q ./test.php
就要執行完后再執行后面的代碼
但是你可以這樣做:
php -q ./test.php > /dev/null &
就可以了,不影響下面的代碼繼續執行。
呵呵,不明白的朋友可以自己google一下。
[
本帖最后由 Haohappy 于 2005-12-6 11:26 編輯 ]
作者: wobushiwo
時(shí)間: 2005-12-5 19:15
QUOTE:
原帖由 Haohappy 于 2005-12-5 16:27 發(fā)表
這里有一個(gè)技巧哦,推薦給這里的朋友們:
如果你執行的是
php -q ./test.php
就要執行完后再執行后面的代碼
但是你可以這樣做:
php -q ./test.php > /dev/null
就可以了,不影響下面的代碼繼 ...
很遺憾,我GOOGLE后還是不明白,我只知道 >/dev/null 是把輸出重定向了,不知道還有啟動(dòng)另一進(jìn)程的
能力,請牛人明示
作者: Haohappy
時(shí)間: 2005-12-6 11:38
呵呵。還有一個(gè)&,不好意思。
$cmd= "php -q ./test.php > /dev/null & "
$pid = exec($cmd);
-q 去掉php信息
> /dev/null 消除shell下的輸出
& 后臺執行
這三步就可以做到?jīng)]有輸出,也不影響下面的代碼執行。
win下:
$wsh = new COM("WScript.Shell");
$phpobj = $wsh->Exec("php -q ./test.php ");
$pid = $phpobj->ProcessID;
有可能會(huì )引起殺毒軟件的報警,呵呵。
作者: wobushiwo
時(shí)間: 2005-12-6 11:40
QUOTE:
原帖由 wobushiwo 于 2005-12-2 20:38 發(fā)表
不好意思,是 + &
請看 13 樓
作者: dulao5
時(shí)間: 2006-6-2 11:38
除了fork, cli下的并發(fā)方式還有一種,看我的例子:
php不支持多線(xiàn)程,但是我們可以把問(wèn)題轉換成“多進(jìn)程”來(lái)解決。由于php中的pcntl_fork只有unix平臺才可以使用,所以本文嘗試使用popen來(lái)替代。
下面是一個(gè)例子:
被并行調用的子程序代碼:
<?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);
}
?>
----------------------------
主調用者程序,由他調用子進(jìn)程,同時(shí)并發(fā)的收集子程序的輸出
<?php
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);
?>
-------------------
下面是我機器上的輸出:
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
**總結:**
**主程序循環(huán)等待子進(jìn)程, 通過(guò)fgets或fread 把子進(jìn)程的輸出獲取出來(lái) , 從時(shí)間戳上看,的確實(shí)現了并發(fā)執行。**
-----------------------------------------------
以后的改進(jìn):
* popen打開(kāi)的句柄是單向的,如果需要向子進(jìn)程交互,可以使用proc_open
* 使用數組和子函數代替while(!feof($handle1) || !feof($handle2) || !feof($handle3) )這種齷齪的寫(xiě)法
* 用fread一次把子進(jìn)程已經(jīng)產(chǎn)生的輸出取完,而不是每次一行。
------------------
我的blog : http://dulao5.blog.hexun.com/3726837_d.html
[
本帖最后由 dulao5 于 2006-6-2 11:39 編輯 ]
作者: dulao5
時(shí)間: 2006-6-2 11:45
一個(gè)并發(fā)執行shell任務(wù)的調度者,本程序讀取一個(gè)任務(wù)文件,把里面的每行命令并發(fā)執行, 可以設置同時(shí)存在的子進(jìn)程數目:
<?
/*
主任務(wù)管理器
并發(fā)的執行子任務(wù)列表
*/
include("../common/conf.php");
include("../common/function.php");
//開(kāi)啟的進(jìn)程數
$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)程列表有空閑,則填充補齊子進(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)閉并記錄下來(lái)
$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);
?>
| http://bbs.chinaunix.net/ |