johnnywang has asked for the wisdom of the Perl Monks concerning the following question:

I'm tring to benchmark the Thread::Queue methods with the following simple code:
use strict; use Thread::Queue; use Benchmark; # this part works fine my $queue = Thread::Queue->new(); timethis(1000, sub{$queue->enqueue(1);}); timethis(1000, sub{$queue->dequeue();}); # this part gets stuck. # but works fine if I change dequeue() to dequeue_nb() my $queue2 = Thread::Queue->new(); timethese(1000, {'Push'=>sub{$queue2->enqueue(1);}, 'Pop'=>sub{$queue2->dequeue();} } );
It seems timethese() somehow get stuck on the dequeue() call, which is blocking if the queue is empty. It works fine if dequeue() is replaced by dequeue_nb(). But why does it get stuck? I thought timethese() does the testing in sequence, not in parallel, so the second test should be the same as the first two timethis(), what's wrong?

Replies are listed 'Best First'.
Re: Benchmark does timethese() in parallell?
by darrellb (Acolyte) on Nov 06, 2004 at 01:45 UTC
    The blocking is a result of "Pop" running before "Push". The input to timethese is a hashref which might imply that their relative ordering is unknown (that was my first guess... that an unordered "keys" was used). However, looking at timethese(), you can see that the incoming keys are sorted. So the Pop timing happens before the Push timing:
    sub timethese{ my($n, $alt, $style) = @_; die usage unless ref $alt eq 'HASH'; my @names = sort keys %$alt; $style = "" unless defined $style; ...
Re: Benchmark does timethese() in parallell?
by BrowserUk (Patriarch) on Nov 06, 2004 at 02:28 UTC

    I see darrellb has answered your question, but it might be worth pointing out that if you benchmark Thread::Queue without loading threads, you are not going to get very useful results. Without threads loaded, when T::Q tries to load threads::shared to gain access to share, lock and the cond_* functions, the use threads::shared; becomes a noop. Hence, you will be benchmarking a normal perl array via a (somewhat slower) OO interface.

    The difference in timings between push/pop with and without threads loaded is quite marked:

    Without:

    Benchmark: timing 1000000 iterations of a_push, b_pop ... a_push: 4 wallclock secs ( 3.31 usr + 0.08 sys = 3.39 CPU) @ 29 +4898.26/s (n=1000000) b_pop: 4 wallclock secs ( 3.91 usr + 0.00 sys = 3.91 CPU) @ 25 +6016.39/s (n=1000000)

    With:

    [ 2:13:30.98] P:\test>junk Benchmark: timing 1000000 iterations of a_push, b_pop ... a_push: 19 wallclock secs (16.02 usr + 3.53 sys = 19.55 CPU) @ 51 +161.36/s (n=1000000) b_pop: 21 wallclock secs (17.52 usr + 2.34 sys = 19.86 CPU) @ 50 +352.47/s (n=1000000)

    The slowdown when locking and sharing are active is to be expected, and is unlikely to be too much of a concern in a threaded application, and there is little point in using T::Q in a non-threaded application.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Benchmark does timethese() in parallell?
by pg (Canon) on Nov 06, 2004 at 03:00 UTC

    From a design point of view, timethese() SHOULD NOT run things in parallel. If it does that, then because of things like thread scheduling, resource sharing etc., you no longer get the true and fair result.

Re: Benchmark does timethese() in parallell?
by Aighearach (Initiate) on Nov 06, 2004 at 01:13 UTC
    I don't have the answer to the problem you're having, but Benchmark::timethese is definately sequencial. To prove this:
    perl -MBenchmark -le '$|++;timethese(10,{one=>sub{print"one"},two=>sub +{print"two"}})'

    --
    Snazzy tagline here