0

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

我有一组 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 => 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 => 24应防止一次启动超过 24 个孩子,所以我不确定在任何给定时刻运行太多是如何发生的。

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

4

2 回答 2

1

我只是分享我对此的发现。

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

sh: fork: retry: No child processes

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

MAX_PROC => 24

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

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

于 2012-07-18T05:44:24.203 回答
0

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

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

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

希望有帮助。

于 2015-03-02T14:22:58.573 回答