2012-04-17 52 views
3

我的問題是這樣的。我正在分流一個進程,以便加速磁盤上文件的訪問時間。我將來自這些文件的任何數據存儲在本地臺上的tmp文件中。理想情況下,在所有進程完成後,我需要訪問該tmp文件並將數據存入數組。然後我斷開tmp文件的鏈接,因爲它不再需要。我的問題是,看起來似乎pcntl_wait()並沒有等到所有子進程完成之後才進入最後一組操作。所以我最終在一些隨機過程完成前斷開該文件。等待所有的pid退出php

我似乎無法找到一個穩定的方式來等待所有進程乾淨地退出然後訪問我的數據。

$numChild  = 0;  
    $maxChild  = 20; // max number of forked processes. 

    // get a list of "availableCabs" 

    foreach ($availableCabs as $cab) { 

      // fork the process 
      $pids[$numChild] = pcntl_fork(); 

      if (!$pids[$numChild]) { 

        // do some work  
        exit(0); 

      } else { 

        $numChild++; 
        if ($numChild == $maxChild) { 

          pcntl_wait($status); 
          $numChild--; 

        } 

      } // end fork 

    } 

    // Below is where things fall apart. I need to be able to print the complete serialized data. but several child processes don't actually exit before i unlink the file. 

    $dataFile = fopen($pid, 'r'); 

    while(($values = fgetcsv($dataFile,',')) !== FALSE) { 
      $fvalues[] = $values; 
    } 

    print serialize($fvalues); 

    fclose($dataFile); 
    unlink($file);  

請注意,我留下了很多關於我在做什麼的代碼,如果我們需要發佈那些問題。

+1

你可以嘗試通過每一個PID循環在'$的PID [$ numChild]'和http://php.net/pcntl_waitpid(這是從pcntl_wait不同)每個。 – 2012-04-17 20:47:32

+0

所以我在'foreach()'循環之外測試? – 2012-04-17 20:49:35

回答

5

嘗試重構您的代碼,以便您有兩個循環 - 一個生成進程和一個等待它們完成的循環。您還應該使用pcntl_waitpid()來檢查特定的進程ID,而不是您正在使用的簡單子計數方法。

事情是這樣的:

<?php 

    $maxChildren = 20; // Max number of forked processes 
    $pids = array();  // Child process tracking array 

    // Get a list of "availableCabs" 

    foreach ($availableCabs as $cab) { 

    // Limit the number of child processes 
    // If $maxChildren or more processes exist, wait until one exits 
    if (count($pids) >= $maxChildren) { 
     $pid = pcntl_waitpid(-1, $status); 
     unset($pids[$pid]); // Remove PID that exited from the list 
    } 

    // Fork the process 
    $pid = pcntl_fork(); 

    if ($pid) { // Parent 

     if ($pid < 0) { 
     // Unable to fork process, handle error here 
     continue; 
     } else { 
     // Add child PID to tracker array 
     // Use PID as key for easy use of unset() 
     $pids[$pid] = $pid; 
     } 

    } else { // Child 

     // If you aren't doing this already, consider using include() here - it 
     // will keep the code in the parent script more readable and separate 
     // the logic for the parent and children 

     exit(0); 

    } 

    } 

    // Now wait for the child processes to exit. This approach may seem overly 
    // simple, but because of the way it works it will have the effect of 
    // waiting until the last process exits and pretty much no longer 
    foreach ($pids as $pid) { 
    pcntl_waitpid($pid, $status); 
    unset($pids[$pid]); 
    } 

    // Now the parent process can do it's cleanup of the results 
+0

感謝您的更新。新分叉這麼多學習。讓我試試看看我在哪裏。 – 2012-04-18 11:23:11

+0

運作良好。謝謝您的幫助。 – 2012-04-18 12:57:17

+0

不用擔心。 :-) – DaveRandom 2012-04-18 12:58:33