1. Problem
You want to have your Perl script issue multiple simultaneous
requests. You could do this because you’re trying to test concurrency
issues (what happens when several users work on the same part of the
application?) or because you’re trying to increase the load that your
server puts on the server. Either way, threads make a logical and
convenient way to make simultaneous requests.
2. Solution
You must have threads for Perl enabled to use the solution in
Example 1.
Example 1. Multithreaded fetching of web pages with Perl
#!/usr/bin/perl use threads; use LWP;
my $PAGE = "http://www.example.com/";
# Ten concurrent threads my $numThreads = 10; my @threadHandles = (); my @results = ();
for ($i = 0; $i < $numThreads; $i++ ) { # create a thread, give it its number as an argument my $thread = threads->create( doFetch, $i, $PAGE ); push( @threadHandles, $thread ); }
# Run through all outstanding threads and record their results. while( $#threadHandles > 0 ) { my $handle = pop(@threadHandles); my $result = $handle->join(); push( @results, $result ); print "result: $result\n"; }
sub doFetch { my $threadNum = shift; my $URL = shift; my $browser = LWP::UserAgent->new; my $response = $browser->get( $URL ); return "thread $i " . $response->status_line; }
|
3. Discussion
The example in Example 1 is pretty
minimal and just shows you the basic techniques. The threads execute in
an unknown order, and they might take any amount of time to run. That’s
part of the point: to simulate a bunch of unrelated web browsers hitting
your application in random order.
One of the best uses of multithreading like this is to test
applications where it is acceptable to have the same account logged in
more than once. Build a subroutine that logs in, executes a function or
two, and tests the resulting output or state, then exits. Now launch a
bunch of threads executing that subroutine.
Threading is an optional module in Perl. It might be compiled into
your Perl, or it might not. If it is not, you either have to get a
threading Perl or give up on running this kind of test. Run the command
perldoc perlthrtut to learn about
threading and how to tell if your implementation has threads
enabled.
Be aware that multithreaded and concurrent programming is hard for many, many reasons.
If you don’t stray far from the example in Example 1, you’ll do alright, but it is very
easy to imagine some simple modifications that are surprisingly hard
to do correctly.
Make sure to use my on all
the variables in your threads. Don’t try to pass data between threads.
Writing to global variables is a sure way to get into trouble when
you’re multithreading. Your programming language (Perl in this case)
will let you do it, but you’ll almost certainly get unexpected
results. Only pass data from the thread to the main program through
the return value in the join()
call. It’s not that there is no other way to pass data around; it’s
just that this is the safest, simplest method if you’ve never done
threads before.
A cobbled-together, threaded Perl script is not a substitute for
a well-planned, properly executed performance test plan. Just because
you can execute a whole bunch of threads, doesn’t mean you’ll
accomplish a lot. You might bog down your Perl program so much that
you actually don’t execute many concurrent processes at all. Do some
experiments to see just how many threads you can realistically get
going at the same time.
Be careful with things like the sleep command in
Perl. In some operating systems, your whole process (i.e.,
all threads) may go to sleep and stop running if
you call sleep in just one of them
or in your main program.