在PHP中等待所有进程ID退出

8
我的问题是这样的。我正在分叉一个进程,以便加速磁盘上文件的访问时间。我将这些文件中的任何数据存储在本地桌面的临时文件中。理想情况下,在所有进程完成后,我需要访问该临时文件并将其数据放入数组中。然后,我取消链接临时文件,因为它不再需要了。我的问题是似乎pcntl_wait()在进行最后一组操作之前并不等待所有子进程都完成。所以我最终会在某个随机进程完成之前取消链接该文件。
我似乎找不到一个可靠的方法来等待所有进程干净地退出,然后访问我的数据。
    $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
你可以尝试循环遍历 $pids[$numChild] 中的每个 pid,并在每个 pid 上使用 http://php.net/pcntl_waitpid(与 pcntl_wait 不同)进行处理。 - Frank Farmer
那么我是在foreach()循环之外测试它吗? - au_stan
1个回答

14

尝试重构你的代码,使其包含两个循环 - 一个用于生成进程,一个用于等待它们完成。同时,你应该使用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

谢谢更新。我对分叉还不熟悉,需要学习很多。让我试一下,看看自己的水平如何。 - au_stan
@DaveRandom 使用这种方法,我们将无法限制生成的子进程的最大数量? - Sohaib
好的,我明白了,我们可以在父级中监控它。 - Sohaib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接