Improving mod_perl Driven Site's Performance -- Part VI: Forking and Executing Subprocesses from mod_perl Page 7

By Stas Bekman (Send Email)
Posted Feb 27, 2001


Notice that exec() never returns unless it fails to start the process. Therefore you shouldn't put any code after exec()--it will be not executed in the case of success. Use system() or back-ticks instead if you want to continue doing other things in the process. But then you probably will want to terminate the process after the program has finished. So you will have to write:

      system "/home/httpd/perl/external.pl" or die "Cannot execute system: ";
      CORE::exit(0);

Another important nuance is that we have to close all STD* stream in the forked process, even if the called program does that.

If the external program is written in Perl you may pass complicated data stuctures to it using one of the methods to serialize Perl data and then to restore it. The Storable and FreezeThaw modules come handy. Let's say that we have program master.pl calling program slave.pl:

  master.pl
  ---------
  # we are within the mod_perl code
  use Storable ();
  my @params = (foo => 1, bar => 2);
  my  = Storable::freeze(\@params);
  exec "./slave.pl",  or die "Cannot execute exec: ";
  slave.pl
  --------
  #!/usr/bin/perl -w
  use Storable ();
  my @params = @ARGV ? @{ Storable::thaw(shift)||[] } : ();
  # do something

As you can see, master.pl serializes the @params data structure with Storable::freeze and passes it to slave.pl as a single argument. slave.pl restores the it with Storable::thaw, by shifting the first value of the ARGV array if available. The FreezeThaw module does a very similar thing.

Starting a Short Running External Program

Sometimes you need to call an external program and you cannot continue before this program completes its run and optionally returns some result. In this case the fork solution doesn't help. But we have a few ways to execute this program. First using system():


  system "perl -e 'print 5+5'"

We believe that you will never call the perl interperter for doing this simple calculation, but for the sake of a simple example it's good enough.

The problem with this approach is that we cannot get the results printed to STDOUT, and that's where back-ticks or qx() come to help. If you use either:

  my  = 'perl -e 'print 5+5'';

or:

  my  = qx{perl -e 'print 5+5'};

the whole output of the external program will be stored in the variable.

Of course you can use other solutions, like opening a pipe (| to the program) if you need to submit many arguments and more evolved solutions provided by other Perl modules like IPC::Open2 which allows to open a process for both reading and writing.

Executing system() or exec() in the Right Way

The exec() and system() system calls behave identically in the way they spawn a program. For example, let's use system() as an example. Consider the following code:

  system("echo","Hi");

Perl will use the first argument as a program to execute, find /bin/echo along the search path, invoke it directly and pass the Hi string as an argument.



Comment and Contribute

Your name/nickname

Your email

(Maximum characters: 1200). You have characters left.