2010-01-06 54 views
4

我有一個需要處理的數據隊列(Amazon SQS),我想用多個進程(在PHP中)來完成。用PHP產生多個進程來處理數據。

我希望孩子工人做這樣的事情(pseduoish代碼):

 


while(true) { 

    $array = $queue->fetchNItems(10); // get 10 items 

    if(!count($array)) 
     killProcess(); 

    foreach($array as $item) { 
     ... // process the item 
     $queue->remove($item); 
    } 

    sleep(2); 
} 

 

我總是需要1個進程正在運行,但在需要的時候我想(叉?)孩子進程,以便它可以幫助更快地處理隊列。

有人可以幫助我一個粗糙的PHP骨架,我需要什麼,或指向我在正確的方向嗎?

我想我需要看看http://php.net/manual/en/function.pcntl-fork.php,但我不知道如何使用它來管理多個進程。

+1

這種事情並不是真的是PHP的目標或擅長。分叉過程比產卵線程昂貴得多,這就是典型的做法。 – cletus 2010-01-06 23:57:40

+1

我可以用線程輕鬆地在Python中完成這件事,但出於具體原因,PHP是唯一可用的選項。 – mmattax 2010-01-07 00:16:01

+0

那麼Python有多線程代碼的問題,最顯着的是CPython上的GIL。 Jython/IronPython沒有這個問題,但我想需要編譯。 – cletus 2010-01-07 08:55:04

回答

2

當你fork一個進程。你重複這個過程。換句話說,副本(fork)包含原始進程的所有內容(包括文件句柄)

那麼,如何知道您是父進程還是分叉進程?

從鏈接頁的例子顯示了這個漂亮的明確

<?php 

$pid = pcntl_fork(); 
if ($pid == -1) { 
    die('could not fork'); 
} else if ($pid) { 
    // we are the parent 
    pcntl_wait($status); //Protect against Zombie children 
} else { 
    // we are the child 
} 

?> 

將其擴展到您想要

<?php 

$pid = pcntl_fork(); 
if ($pid == -1) { 
    die('could not fork'); 
} else if ($pid) { 
    // we are the parent 
    pcntl_wait($status); //Protect against Zombie children 
} else { 
    // we are the child 
    while(true) { 

     $array = $queue->fetchNItems(10); // get 10 items 

     if(!count($array)) { 
      exit(); 
     } 

     foreach($array as $item) { 
       ... // process the item 
       $queue->remove($item); 
     } 

     sleep(2); 
    } 
} 

?> 

這將在派生進程創造什麼(在這種情況下浪費)使用循環來創建多個進程。當孩子完成退出時會殺死孩子的過程。和pcntl_wait()將返回,允許父母繼續。我不確定關於PHP,但如果父進程死亡或退出,即使孩子沒有完成,它也會終止子進程。因此pcntl_wait。如果您產生多個孩子,則需要更復雜的系統。

也許而不是分叉你應該看一下exec函數的範圍?

一個告誡。

分叉過程可能會產生問題,當孩子退出時數據庫句柄被關閉等。如果出現問題,您也可以使用多個進程來終止服務器。花費大量的時間玩和測試和閱讀。

DC

0

我知道這是一個古老的線程,但看起來像它可以使用一個更完整的答案。這是我通常在PHP中產生多個進程的方式。

謹慎的一句話:PHP was meant to die.意思是說,語言意味着要執行幾秒鐘然後退出。儘管PHP中的垃圾清理已經走過了很長的路,但要小心。監視您的進程,以發現意外的內存消耗或其他異常情況。在你設置並忘記它之前,一切都像鷹一樣觀看,即使如此,仍然會偶爾檢查一下流程,或者在出現問題時自動通知它們。

當我打字的時候,看起來像是一個好主意,拍到github

當準備運行該程序時,我建議在日誌上做一個尾部-f來查看輸出。

<?php 
/* 
* date: 27-sep-2015 
* auth: robert smith 
* info: run a php daemon process 
* lic : MIT License (see LICENSE.txt for details) 
*/  
$pwd = realpath(""); 

$daemon = array(
    "log"  => $pwd."/service.log", 
    "errorLog" => $pwd."/service.error.log", 
    "pid_file" => $pwd."/", 
    "pid"  => "", 
    "stdout" => NULL, 
    "stderr" => NULL, 
    "callback" => array("myProcessA", "myProcessB") 
); 

/* 
* main (spawn new process) 
*/ 
foreach ($daemon["callback"] as $k => &$v) 
    { 
    $pid = pcntl_fork(); 

    if ($pid < 0) 
    exit("fork failed: unable to fork\n"); 

    if ($pid == 0) 
    spawnChores($daemon, $v); 
    } 

exit("fork succeeded, spawning process\n"); 
/* 
* end main 
*/ 

/* 
* functions 
*/ 
function spawnChores(&$daemon, &$callback) 
    { 
    // become own session 
    $sid = posix_setsid(); 

    if ($sid < 0) 
    exit("fork failed: unable to become a session leader\n"); 

    // set working directory as root (so files & dirs are not locked because of process) 
    chdir("/"); 

    // close open parent file descriptors system STDIN, STDOUT, STDERR 
    fclose(STDIN); 
    fclose(STDOUT); 
    fclose(STDERR); 

    // setup custom file descriptors 
    $daemon["stdout"] = fopen($daemon["log"], "ab"); 
    $daemon["stderr"] = fopen($daemon["errorLog"], "ab"); 

    // publish pid 
    $daemon["pid"] = sprintf("%d", getmypid()); 
    file_put_contents($daemon["pid_file"].$callback.".pid", $daemon["pid"]."\n"); 

    // publish start message to log 
    fprintf($daemon["stdout"], "%s daemon %s started with pid %s\n", date("Y-M-d H:i:s"), $callback, $daemon["pid"]); 

    call_user_func($callback, $daemon); 

    // publish finish message to log 
    fprintf($daemon["stdout"], "%s daemon %s terminated with pid %s\n", date("Y-M-d H:i:s"), $callback, $daemon["pid"]); 

    exit(0); 
    } 

function myProcessA(&$daemon) 
    { 
    $run_for_seconds = 30; 
    for($i=0; $i<$run_for_seconds; $i++) 
    { 
    fprintf($daemon["stdout"], "Just being a process, %s, for %d more seconds\n", __FUNCTION__, $run_for_seconds - $i); 
    sleep(1); 
    } 
    } 

function myProcessB(&$daemon) 
    { 
    $run_for_seconds = 30; 
    for($i=0; $i<$run_for_seconds; $i++) 
    { 
    fprintf($daemon["stdout"], "Just being a process, %s, for %d/%d seconds\n", __FUNCTION__, $i, $run_for_seconds); 
    sleep(1); 
    } 
    } 
?>