Php 如何强制执行最大数量的分叉子项?

Php 如何强制执行最大数量的分叉子项?,php,c,fork,process-management,Php,C,Fork,Process Management,编辑:我已经标记了这个C,希望得到更多的响应。与其说是具体的语言实现,不如说是我感兴趣的理论。因此,如果您是一名C代码编写者,请将以下PHP视为伪代码,并随时以C语言编写的答案进行响应 我试图通过让PHP CLI脚本以并行方式而不是串行方式执行其任务来加快它的速度。这些任务彼此完全独立,因此它们的开始/完成顺序无关紧要 以下是原始脚本(注意,为了清晰起见,所有这些示例都被剥离): 现在我想扩展它,这样一次最多有10个孩子活跃。最好的处理方法是什么?我尝试过一些事情,但运气不太好。man 2 se

编辑:我已经标记了这个C,希望得到更多的响应。与其说是具体的语言实现,不如说是我感兴趣的理论。因此,如果您是一名C代码编写者,请将以下PHP视为伪代码,并随时以C语言编写的答案进行响应

我试图通过让PHP CLI脚本以并行方式而不是串行方式执行其任务来加快它的速度。这些任务彼此完全独立,因此它们的开始/完成顺序无关紧要

以下是原始脚本(注意,为了清晰起见,所有这些示例都被剥离):

现在我想扩展它,这样一次最多有10个孩子活跃。最好的处理方法是什么?我尝试过一些事情,但运气不太好。

man 2 setrlimit


这将是每个用户,这可能是您想要的。

我能想到的最好办法是将所有任务添加到一个队列中,启动您想要的最大线程数,然后让每个线程从队列中请求一个任务,执行该任务并请求下一个任务。当没有更多的任务要做时,不要忘记让线程终止。

分叉是一项昂贵的操作。从外观上看,您真正想要的是多线程,而不是多线程处理。区别在于线程比进程轻得多,因为线程共享一个虚拟地址空间,而进程有单独的虚拟地址空间

我不是一个PHP开发人员,但是快速的Google搜索显示PHP本机不支持多线程,但是有一些库可以完成这项工作

不管怎样,一旦你知道了如何产生线程,你应该知道有多少线程产生。为了做到这一点,您需要知道应用程序的瓶颈是什么。瓶颈是CPU、内存还是I/O?您已经在评论中指出您是网络绑定的,网络是一种I/O类型

如果您是CPU受限的,那么您只会获得与CPU内核相同的并行性;如果有更多的线程,那么你只是在浪费时间进行上下文切换。假设您可以计算出要生成的线程总数,那么您应该将工作划分为这么多个单元,并让每个线程独立处理一个单元

如果内存受限,那么多线程将没有帮助

由于您是受I/O限制的,所以计算要生成多少线程就有点棘手了。如果所有工作项的处理时间几乎相同,且差异非常小,则可以通过测量一个工作项所需的时间来估计要生成多少线程。然而,由于网络数据包往往具有高度可变的延迟,因此不太可能出现这种情况

一种选择是使用线程池——创建一大堆线程,然后针对要处理的每个项目,查看池中是否有空闲线程。如果有,则让该线程执行工作,然后转到下一项。否则,您将等待线程可用。选择线程池的大小很重要——太大了,而且你在浪费时间进行不必要的上下文切换。太少了,你等待线程的次数太多了

另一种选择是放弃多线程/多处理,而只做异步I/O。因为您提到您正在使用单核处理器,所以这可能是最快的选择。您可以使用诸如测试套接字是否有可用数据之类的函数。如果有,您可以读取数据,否则您将转到另一个套接字。这需要做更多的簿记工作,但当数据在另一个套接字上可用时,可以避免等待数据进入一个套接字

如果您想避开线程和异步I/O,坚持使用多处理,那么如果每项处理的成本足够高,这仍然是值得的。然后,您可以这样进行分工:

$my_process_index = 0;
$pids = array();

// Fork off $max_procs processes
for($i = 0; $i < $max_procs - 1; $i++)
{
  $pid = pcntl_fork();
  if($pid == -1)
  {
    die("couldn't fork()");
  }
  elseif($pid > 0)
  {
    // parent
    $my_process_index++;
    $pids[] = $pid
  }
  else
  {
    // child
    break;
  }
}

// $my_process_index is now an integer in the range [0, $max_procs), unique among all the processes
// Each process will now process 1/$max_procs of the items
for($i = $my_process_index; $i < length($items); $i += $max_procs)
{
  do_stuff_with($items[$i]);
}

if($my_process_index != 0)
{
  exit(0);
}
$my\u process\u index=0;
$pids=array();
//分叉$max_进程
对于($i=0;$i<$max_procs-1;$i++)
{
$pid=pcntl_fork();
如果($pid==-1)
{
死(“不能叉()”;
}
elseif($pid>0)
{
//母公司
$my_process_index++;
$pid[]=$pid
}
其他的
{
//孩子
打破
}
}
//$my_process_index现在是[0$max_procs]范围内的整数,在所有进程中是唯一的
//每个进程现在将处理项目的1/$max_进程
对于($i=$my_process_index;$i
没有系统调用来获取子PID列表,但是
ps
可以为您这样做

--ppid
开关将为您的进程列出所有子进程,因此您只需计算由
ps
输出的行数


或者,您可以维护自己的计数器,该计数器将在
fork()上递增
并在
SIGCHLD
信号上减量,假设
ppid
对fork'ed处理保持不变。

哈!我喜欢这个标题-我不得不来读这个问题,因为这个标题让我想起冷酷无情的独裁者用叉子折磨他们的孩子来报复政治恶棍……哈。我很高兴我的问题是它是什么,而不是你认为它是什么:-)如果我想在应用程序的级别上做这个怎么样?这是一个可以从应用程序调用的系统调用。它通常用于限制核心、核心转储、文件描述符等。你也可以用它来限制CPU利用率(我经常这样做),以及进程的数量。感谢您的回答,我将尝试一下。我在一些地方读到,在Unix fork()中,实际上没有那么昂贵,这就是线程的实现方式。这是过时/不正确的信息吗?“你只需要获得与CPU核一样多的并行性;再多的线程,你只是在浪费时间做上下文切换。”好吧,在我的例子中,我只有1个c
<?php

ini_set('max_execution_time', 0); 
ini_set('max_input_time', 0); 
set_time_limit(0);

$items = range(0, 100);

function do_stuff_with($item) { echo "$item\n"; }

$pids = array();
foreach ($items as $item) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("couldn't fork()");
    } elseif ($pid > 0) {
        // parent
        $pids[] = $pid;
    } else {
        // child
        do_stuff_with($item);
        exit(0);
    }   
}

foreach ($pids as $pid) {
    pcntl_waitpid($pid, $status);
}
$my_process_index = 0;
$pids = array();

// Fork off $max_procs processes
for($i = 0; $i < $max_procs - 1; $i++)
{
  $pid = pcntl_fork();
  if($pid == -1)
  {
    die("couldn't fork()");
  }
  elseif($pid > 0)
  {
    // parent
    $my_process_index++;
    $pids[] = $pid
  }
  else
  {
    // child
    break;
  }
}

// $my_process_index is now an integer in the range [0, $max_procs), unique among all the processes
// Each process will now process 1/$max_procs of the items
for($i = $my_process_index; $i < length($items); $i += $max_procs)
{
  do_stuff_with($items[$i]);
}

if($my_process_index != 0)
{
  exit(0);
}