在Perl中为什么“在BEGIN内部岔开......一个可怕的前景”?

时间:2014-03-27 16:50:03

标签: perl fork

作为对另一个SO Q& A的评论的一部分,用户注意到:

  BEGIN内部的叉子是一个可怕的前景

为什么这是一个“可怕的前景”? (在技术层面 - 让我们放弃设计的可读性或美观)

use strict;
BEGIN {
    # Begin block to fork off a child process.
    # This is done in BEGIN, because otherwise My::HeavyModule module
    # will be loaded BEFORE the fork and thus inherited by child process
    # which is something we want to avoid

    my $init = 1; # Some lightweight init code

    if (my $pid = fork()) {
        # Nothing to do here, proceed to the rest of the main program
    } else {
        die "cannot fork" unless defined $pid;
        print "Child process started!\n";
        exit 0;
    }
} # End BEGIN block

use My::HeavyModule; # Very heavyweight on both startup time and memory 

# Start parent process logic using My::HeavyModule;

为了清楚起见:询问是否有更好的方法来实现此代码正在执行的操作。我问为什么这种方法被称为“可怕”,而不是它是否可以被更好的东西取代。

2 个答案:

答案 0 :(得分:6)

我写了以下你所指的评论:

  fork内的BEGIN是一个可怕的前景。您还可以使用eval "string"require延迟某些部分的编译,但这也存在问题。

虽然不是因为技术原因(除了dan1111 mentionedexplicit portability warning in perlfork之外没有),但是因为它完全打破了我对任何程序行为的期望。

  • 每段代码都有编译时间。我希望在这里设置包和类,也许会发生一些元编程。

  • 然后,有一个运行时间,在此期间我们的程序的主要控制流程发生,在此期间正在执行该程序的工作。

Perl使这个简单的区别变得复杂,因为一个块的编译时间是另一个块的运行时间(例如,通过BEGINuseevalrequire)。但总有一个明确的参考点:$0的阶段,该程序最初被调用(另见${^GLOBAL_PHASE})。在主脚本的编译时,总会出现 做一个好主意的好主意的情况,但这并不一定是这样做的最佳做法 - 相反,因此我反对这样做会是一个“可怕的前景”。

如果你的程序的主要工作是启动另外两个独立程序,它可能如下所示:

use strict;
use warnings;

my $pid = fork;
if (not defined $pid) {
    die "welp, can't fork: $!";
}
if ($pid) {
    exec $^X, "heavy_program_you_intended_to_be.pl", @ARGV;
}
else {
    ... # background yourself, etc.
    exec $^X, "light_program_you_intended_to_kick_off.pl";
}

但它不会在BEGIN中分叉。我认为这是可以使用Perl执行某些操作的众多示例之一,但这并不意味着您应该

答案 1 :(得分:4)

  1. 在您知道整个事件是否成功编译之前,您正在运行程序的一个过程。这似乎不是你想要做的事情。
  2. 可读性。
  3. 漂亮的设计。
  4. (对不起,我知道你说要忽略最后两个。但这不公平,是吗?两者都是代码是否是“可怕前景”的重要考虑因素。)

    另一方面,我喜欢你可以在Perl中做这样的不明智的事情。而且我不会告诉你需要重新编写代码。这在很大程度上取决于这种情况:这个代码的任务关键性如何?它需要多么可维护?有多少其他开发人员会参与其中?等