【问题标题】:Forks::Super sh: fork: retry: No Child Processforks::Super sh: fork: retry: No Child Process
【发布时间】:2012-07-17 01:26:19
【问题描述】:

最终更新:我真的不知道如何解释,但问题不再发生。如果我找出解决问题的方法,我会发布答案。

我有一组 perl 脚本,用于在 16 核 Fedora 17 机器上执行大量类似的命令。到目前为止,每次我需要更改命令的生成方式时,我都会使用其中一个旧脚本作为模板编写一个新脚本,而且我之前从未遇到过代码问题(嗯,自从我编写了无论如何,原始的脚本集)。重要的是要注意旧脚本仍然可以正常工作,所以我认为这不是系统问题,我主要关注我(可能)搞砸代码的地方。

这是一个工作脚本的精简版本:

use Forks::Super MAX_PROC => 24, ON_BUSY => 'block';
#...
foreach my $fi (@FILES){
    #...
    $runMe = 'java -Xmx2048m weka.classifiers.'. $class .' -t '. $TR .' -T '. $TE .' -c 1 > '. $OUT;
    fork { cmd =>  $runMe};
    #...
}
waitall;
print("\nDone!\n");

以下是已损坏脚本的精简版:

use Forks::Super MAX_PROC => 24, ON_BUSY => 'block';
#...
foreach my $n (@FI){
    if($n =~ m/^\d+$/){
            #...
        foreach my $f (@files){
            if($f =~ m/(\d+).arff/){
                print "starting interval $1 ... \n";
                #...
                $runMe = 'java -Xmx2048m weka.classifiers.'. $class .' -t '. $TR .' -T '. $TE .' -c 1 > '. $OUT;
                fork { cmd =>  $runMe );                
            }
        }
    }
}
waitall;
print("\nDone!\n");

这是脚本的输出(部分):

starting interval 12 ...
starting interval 3 ...
sh: fork: retry: No child processes
starting interval 30 ...
starting interval 6 ...
Use of uninitialized value $signal_pid in print at /usr/local/share/perl5/Forks/Super/Job.pm line 991, <DATA> line 261.
Use of uninitialized value $exec_pid in waitpid at /usr/local/share/perl5/Forks/Super/Job.pm line 918, <DATA> line 261.

错误sh: fork: retry: No child processesuninitialized value $signal_piduninitialized value $exec_pid 一遍又一遍地出现在输出中看似随机的点,并且随着程序运行时间的延长而越来越多。

更新: $ ulimit -a 返回 max user processes (-u) 1024,这比我为 Forks::Super 设置的 24 以及我在这台远程机器上运行的 4 个终端要多得多。鉴于另一个脚本工作正常并且这个返回No child processes,我认为我不能清理/等待我在第二个脚本中创建的所有进程。我只是想不通在第一个和第二个脚本之间对waitall 的调用有什么不同。

更新: 使用Forks::Super::Debug =&gt; 1 选项,这里是一些有代表性的输出:

starting interval 30 ...
14694 23:24:05.735:  New job created: {pid=;state=NEW;cmd=java -Xmx2048m weka.classifiers.lazy.IBk -K 3 -t /foo/arff_files/$
14703 23:24:05.735:  Signal pid for 14703 is 14708
14694 23:24:05.736:  fork(): {pid=;state=NEW;style=cmd;cmd=[java -Xmx2048m weka.classifiers.lazy.IBk -K 3 -t /foo/arff_file$
14694 23:24:05.736:  _can_launch(): system not busy. launch ok.
14694 23:24:05.736:  fork: launch approved for job
14694 23:24:05.736:  Job will use /bar/.fhfork14694/.fh_007.signal to get signal pid.
14707 23:24:05.737:  Executing command [ java -Xmx2048m weka.classifiers.lazy.IBk -K 3 -t /home/share/data/arff_files/trainers_l1o_curv$
Use of uninitialized value $signal_pid in print at /usr/local/share/perl5/Forks/Super/Job.pm line 991, <DATA> line 261.
Use of uninitialized value $signal_pid in concatenation (.) or string at /usr/local/share/perl5/Forks/Super/Job.pm line 995, <DATA> lin$
14707 23:24:05.737:  Signal pid for 14707 is
Use of uninitialized value $exec_pid in waitpid at /usr/local/share/perl5/Forks/Super/Job.pm line 918, <DATA> line 261.
14707 23:24:05.737:  waitpid returned -1, exit code of 14707 was -1 72057594037927935
starting interval 6 ...
14694 23:24:05.739:  New job created: {pid=;state=NEW;cmd=java -Xmx2048m weka.classifiers.lazy.IBk -K 3 -t /foo/arff_files/$
14694 23:24:05.739:  fork(): {pid=;state=NEW;style=cmd;cmd=[java -Xmx2048m weka.classifiers.lazy.IBk -K 3 -t /foo/arff_file$
14694 23:24:05.739:  _can_launch(): system not busy. launch ok.
14694 23:24:05.740:  fork: launch approved for job
14694 23:24:05.740:  Job will use /bar/programs/.fhfork14694/.fh_008.signal to get signal pid.
14694 23:24:05.740:  launch(): CORE::fork() returned undefined!
current file is 2

我相当确定问题在于进程没有及时消亡/被清理以创建新进程。 ps -aux 同意有很多孩子在奔跑,即使他们在我杀死父母之前和之后都没有出现在 top 的前 50 行中。 waitall; 调用应该防止脚本在其孩子还活着的时候退出,MAX_PROC =&gt; 24 应该防止一次启动超过 24 个孩子,所以我不确定有太多正在运行的脚本是怎么发生的任何给定的时刻。

如果waitall 是我遇到麻烦的原因,那么每次连续调用脚本时问题会变得更糟,这就是我看到的情况。但如果是这种情况,我不应该在top 中看到我在做什么。看top的时候,一开始看到有24个孩子在跑,第一次跑完后看到孩子的数量减少到没有,然后再执行,又有24个孩子在执行.. . 这是我在其他脚本中看到的正常模式。但是稍后,或者如果我终止脚本(使用pkill perlpkill java 确保没有与任务相关的进程处于活动状态)并重新启动它,那么我会看到大量错误消息和少量但零星的数字top 中的儿童。

【问题讨论】:

    标签: perl process fork


    【解决方案1】:

    由于没有提供答案,我想我会加入这个较旧的线程,因为我刚刚经历过这个。我的 Fedora 20 盒子已经运行好几个星期了,周五离开办公室没有问题,周一早上进来,发现我无法解锁我的 xscreensaver 会话。任何键或鼠标移动只会导致屏幕闪烁。按 Ctrl-Alt-F2 得到一个文本控制台,我登录并得到了你列出的相同消息。我发出的每个命令(首先是 sudo su -)都给了我“bash: fork: retry: no child processes”,然后最终该命令将完成。

    我终于能够查看一个进程列表,似乎没有什么异常,因为我的 ulimit 设置是正常的,但是我在 maxuprc 和打开文件的限制下。内存使用也很好。我确实注意到的一件事是,我的 firefox 进程(和 firefox 插件容器进程)都在消耗过多的 CPU,仅从上周开始就消耗了数百小时。我杀死了这两个进程,然后我的系统很好,之后就没有问题了。

    我不记得我打开了哪些选项卡,即使有任何被认为有问题,但无论哪种方式,这些过程(或至少其中一个)肯定是原因。

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      我只是分享我在这方面的发现。

      工作脚本只包含一个循环,而损坏的脚本包含一个嵌套循环,假设它的进程比工作脚本多。

      sh: fork: retry: No child processes
      

      没有子进程是一个系统错误,表示它不能派生更多。所以在执行的时候,代码可能会fork更多的进程,从而导致这个错误。

      MAX_PROC => 24
      

      您一次只需要执行 24 个进程,如果它尝试分叉超过这 24 个,根据ON_BUSY =&gt; 'block',它将等待并重试创建子进程,直到成功。在模块文档Forks::Super 中,它说如果系统分叉调用失败,它将失败。从错误中您可以清楚地看出系统无法进行更多分叉。只需添加一个$count++ 变量并找出将分叉的进程数。也请尝试Forks::Super::DEBUG,以便您获得更多线索。

      $ ulimit -a 不返回最大进程数,实际上它返回用户可以运行的最大线程数。试试ps aux,这样您就可以更清楚地了解当前正在运行的进程。

      【讨论】:

      • 谢谢-我明天会研究这些并更新。嵌套循环并不意味着更多的进程——它完全取决于任何给定目录中的文件数量。在这种情况下,它实际上是更少的进程。此外,其他脚本运行了数天并派生了数万个进程而没有问题,而使用这个新的测试设置总共只有约 2,000 个进程可以运行。我认为并希望 Forks::Super 不会分叉,除非它实际上是在创建一个真正的工作进程,否则它会在任何时候不得不阻塞很长时间时失败。
      • 也就是说,我完全使用那个模块的原因之一是因为它声称控制活动进程的数量并将其限制为MAX_PROC,所以如果它不这样做那么我可能应该提交一个错误。
      • 但是在模块文档中它说 如果系统分叉调用失败,它将失败 。还尝试在执行损坏的代码后立即执行工作代码。所以如果服务器不能派生新的孩子,在工作代码中也必须显示错误。
      • 是的,系统分叉调用失败。是的,如果我运行脚本的次数足够多,那么错误会变得非常严重,以至于我必须重新启动机器,因为我什至不能ls 没有错误。我认为这一定是因为我正在创建的进程没有消亡/正在清理,因此它们会在下次调用脚本时一直存在(我发布的脚本连续多次使用不同的参数调用)。那么,我的问题在于waitall; 命令,该命令显然无法正常运行。调试器结果将在几个小时后出炉。
      • 调试输出已编辑到问题中 - 我仍然不确定原因是什么。
      猜你喜欢
      • 2020-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-10
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      相关资源
      最近更新 更多