Wednesday, July 03, 2013

Perl thread vs fork


Here are some advice about when to use "thread" and when to use "fork" in Perl. In Perl, thread and fork they each certaily have their pros and cons. Based on my Perl experience and articles I read, here is my list of pros and cons:

  • Threads copied all data anyway, as a thread would, but did it all upfront
  • Threads didn't always clean up complex resources on exit; causing a slow memory leak that wasn't acceptable in what was intended to be a server
  • Several modules didn't handle threads cleanly, including the database module I was using which got seriously confused.
  • Processes have their own address space. Threads share the same address space. This means that all global data is shared by threads.
  • Processes can run as different users and with different permissions, for example calling setuid() after a fork.
  • If a thread causes a severe problem it can bring down all the threads and terminate the program. With processes only one instance would terminate. This problem is more common in languages such as C/C++ though.
  • You use different methods for communication and synchronization between threads and processes.
  • If the lifetime of a thread/process is short, threads perform better since threads are created faster than processes. Otherwise the performance is usually comparable, depending on the communication patterns between threads/processes of course.
  • fork's shared variables still very limited
  • fork has fewer memory leaks
  • fork has process isolation
  • fork has fewer race conditions

Below are two examples on how to user thread() and fork()
fork():

#!/usr/bin/perl
 
use strict;
use warnings;
 
print "Starting main program\n";
my @childs;
 
for ( my $count = 0; $count < 5; $count++) {
        my $pid = fork();
        if ($pid) {
            # Parent
            print "pid is $pid, parent $$\n";
            push(@childs, $pid);
        } elsif ($pid == 0) {
                # child
                sub1($count);
                exit 0;
        } else {
                die "couldnt fork: $!\n";
        }
 
}
 
foreach (@childs) {
        my $tmp = waitpid($_, 0);
         print "done with pid $tmp\n";
 
}
 
print "End of main program\n";
 
 
sub sub1 {
        my $num = shift;
        print "started child process for  $num\n";
        sleep $num;
        print "done with child process for $num\n";
        return $num;
}

The result will be:

$ ./fork.pl

Start main program...
pid is 16035, parent pid is 16034
Started child process for 0
Done with child process for 0
pid is 16036, parent pid is 16034
Started child process for 1
pid is 16037, parent pid is 16034
Started child process for 2
pid is 16038, parent pid is 16034
Started child process for 3
pid is 16039, parent pid is 16034
Done with pid 16035
Started child process for 4
Done with child process for 1
Done with pid 16036
Done with child process for 2
Done with pid 16037
Done with child process for 3
Done with pid 16038
Done with child process for 4
Done with pid 16039
End of main program

Remember that the PID of the child process is returned in parent's thread of execution, and a 0 is returned in the child's process of execution. On failure, a -1 will be returned in the parent's context.


Thread():
#!/usr/local/roadm/bin/perl
# This is compiled with threading support
 
use strict;
use warnings;
use threads;
use threads::shared;
 
print "Starting main program\n";
 
my @threads;
for ( my $count = 1; $count <= 10; $count++) {
        my $t = threads->new(\&sub1, $count);
        push(@threads,$t);
}
foreach (@threads) {
        my $num = $_->join; # Wait for threads to finish executuion
        print "done with $num\n";
}
print "End of main program\n";
 
sub sub1 {
        my $num = shift;
        print "started thread $num\n";
        sleep $num;
        print "done with thread $num\n";
        return $num;
}

The result will be:

$ ./thread.pl
The main program starts...
Started thread 1
Started thread 2
Started thread 3
Started thread 4
Started thread 5
Done with thread 1
Done with 1
Done with thread 2
Done with 2
Done with thread 3
Done with 3
Done with thread 4
Done with 4
Done with thread 5
Done with 5
End of main program

No comments: