2011-01-23 84 views
8

我有一個用於通過CLI(cmd,bash等)執行程序的實用程序函數。它返回3個項目的數組:STDOUT,STDERREXIT CODEPHP proc_open多次打開

到目前爲止,它一直很好地工作沒有問題。事實上,我所遇到的問題並不妨礙它的功能,但我擔心的是性能。

問題是,在某些情況下,PHP多次運行相同的命令(在我的情況下是3次),即使它應該只做一次。

/** 
* Executes a program and waits for it to finish, taking pipes into account. 
* @param string $cmd Command line to execute, including any arguments. 
* @param string $input Data for standard input. 
* @param boolean $log Whether to log execution failures or not (defaults to true). 
* @return array Array of "stdout", "stderr" and "return". 
*/ 
public static function execute($cmd,$stdin=null,$log=true){ 
    //static $once=true; if(!$once)die; $once=false; 
    $proc=proc_open($cmd, array(
     0=>array('pipe','r'), 
     1=>array('pipe','w'), 
     2=>array('pipe','w') ), $pipes); 
    fwrite($pipes[0],$stdin);    fclose($pipes[0]); 
    $stdout=stream_get_contents($pipes[1]); fclose($pipes[1]); 
    $stderr=stream_get_contents($pipes[2]); fclose($pipes[2]); 
    $return=proc_close($proc); 
    if($return!=0 && $log) 
     xlog('Error: Program execution returned failure.',$stdout,$stderr,$return); 
    return array('stdout'=>$stdout, 'stderr'=>$stderr, 'return'=>$return); 
} 

請注意註釋行(第9行)。那是爲了測試。我使它能夠確保目標程序只運行一次(我想我的代碼可能會以某種方式調用相同的函數)。 但即使啓用該行,該程序仍然運行多次。

事實上,我在我的代碼中執行相同的程序(在不同的場合)有兩個地方。兩個命令行都是相同的。

但是,有一次,該程序運行一次,而在這種情況下,PHP運行該程序3次。

我一直在Process Explorer下監視和看到這個行爲。我正在使用Windows 7 x64。該程序是32位的,就像PHP一樣。

編輯:有問題的程序是自定義開發的,它不會打開新的進程。

+4

使用另一個進程的工具來驗證觀察。你沒有提到它是什麼程序(可能自己分成子進程)。 – mario 2011-01-23 21:10:22

+0

@Christian:我們如何檢查它?正如你所說,你沒有提到它是什麼程序。馬里奧是完全正確的;你應該聽他的。 – 2011-01-23 23:09:09

回答

1

您的代碼來測試它只運行一次看起來有瑕疵。

如果你有2個php進程運行,他們將不會共享一個靜態變量。所以有可能你有同時發生的請求導致它不止一次運行。

其次,您應該在功能結束時將 $once設置爲false,否則 die將永遠不會到達。

嘗試添加一些日誌記錄以查看函數是否被兩次調用。

創建一些只運行外部應用程序的單元/壓力測試。如果你看到多個進程,那麼你的應用程序有一些錯誤的東西,而不是php代碼。

0

這很奇怪。沒有完整的代碼就很難弄清楚。

如果你強調你的服務器多次調用同一頁面,我最好打賭它可能與CPU循環過程有關。 PHP沒有時間將靜態變量設置爲false,因爲與此方法相同,還有另一個請求。其他的可能性是,PHP無法正確隔離靜態值,並且在PHP對數據進行同步之前,對此方法的不同請求可以讀取不同的內存位置。

0

我知道這可能不是最好的選擇,但這就是我所做的。雖然這是在Linux上,但我相信有辦法將其移植到Windows。

我做了什麼,運行pgrep並檢查是否已經存在這樣的命令,如果它確實退出。 正如你所說,你正在運行相同的命令(具有確切的參數),所以只要檢查是否有一個命令正在運行,並分別採取行動。

我用這個命令:

$pid = shell_exec('pgrep -cfx "/* My command */"'); 
if ($pid > 1) return -1;