As part of a comment on another SO Q&A, a user noted that:
fork inside BEGIN is a horrible prospect
Why is that a "horrible prospect"? (on a technical level - let's leave aside readability or prettiness of design)
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;
Just to be clear: I am NOT asking if there are better ways to achieve what this code is doing. I'm asking why this approach was called "horrible", NOT whether it can be replaced by something that may be better.
I wrote the following comment which you are referring to:
fork
insideBEGIN
is a horrible prospect. You could also delay compilation for some parts usingeval "string"
orrequire
, but that also has its issues.
although not because of technical reasons (there are none beyond what dan1111 mentioned, and an explicit portability warning in perlfork
), but because it completely broke my expectations about any programs behaviour.
Each piece of code has a compile time. I expect that packages and classes will be set up here, and maybe that some metaprogramming takes place.
Then, there is a run time during which the main control flow of our program occurs, during which the job of this program is being carried out.
Perl complicates this simple distinction in that one block's compile time is another block's run time (e.g. via BEGIN
or use
or eval
or require
). But there is always a clear reference point: The phase of $0
, the program originally being invoked (see also ${^GLOBAL_PHASE}
). There will always be cases where it is a good idea to do funky things during the main script's compile time, but this doesn't necessitate that doing so would be a best practice – on the contrary, and thus my objection that doing so would be a “horrible prospect”.
If the main job of your program is to kick off two other independent programs, it might look like this:
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";
}
But it would not fork in a BEGIN
. I think this is one of many examples where you can do something with Perl, but this doesn't mean you should.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With