in reply to Re^4: Threads From Hell #1: How To Share A Hash [SOLVED]
in thread Threads From Hell #1: How To Share A Hash [SOLVED]
Your diagram (whilst probably correct for this case) is too prescriptive. It implies that the work is dolled out like kids with Smarties: 1 for you, 1 for you...
But imagine (or try) that the list of numbers was 1000 randomly chosen from 1 .. 2000, and in any order.
Then you'd see that one thread might successively happen to get runs of small (say 1 or 2 digit) numbers that take little time; whilst another thread might happen to always get 4-digit numbers that take longer; with the result that by the end, the first thread may have processed many more items than the second.
But they will both have processed nearly the same number of clock cycles and will end within a few milliseconds or so of each other.
That's one of the beauties of the queue architecture is that it is inherently self-balancing:
#! perl -slw use strict; use threads; use threads::shared; use Thread::Queue; use Math::BigInt; use List::Util qw[ shuffle ]; use Time::HiRes qw[ time ]; use Data::Dump qw[ pp ]; use feature qw(say); our $T //= 4; my %result : shared; sub process { my $Q = shift; my $n = 0; while( my $number = $Q->dequeue ) { my $factorial = factorial($number); lock %result; $result{$number} = $factorial->bstr; ++$n; } printf "[%2u] terminating at %f; having processed %u values\n", th +reads->tid, time(), $n; } sub factorial { my $number = shift; Math::BigInt->bfac($number); } my $start = time; my $Q = new Thread::Queue; $Q->enqueue( (shuffle 1..2000 )[ 0 .. 999 ], (undef) x $T ); my @threads = map { threads->create( \&process, $Q ); } 1 .. $T; $_->join for @threads; my $end = time; printf "Took %.6f seconds\n", $end - $start;
Outputs:
C:\test>1126584-q [ 4] terminating at 1431869328.993618; having processed 280 values [ 1] terminating at 1431869329.076621; having processed 305 values [ 3] terminating at 1431869329.094198; having processed 190 values [ 2] terminating at 1431869329.102986; having processed 225 values Took 17.553564 seconds
The only guarantee is that eventually all the work items are processed and each of the 4 threads will dequeue an undef and so end its loop.
It does mean that work items cannot themselves be undef (or any non-true value unless you modify the loop to: while( defined( my $number = $Q->dequeue ) ){).
And later versions of Thread::Queue acquired, (amongst a lot of dross), an end() method which can be used as an alternative to queueing undef's, but the implementation leaves a lot to be desired; and old (tried and tested) programming habits die hard :)
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^6: Threads From Hell #1: How To Share A Hash [SOLVED]
by karlgoethebier (Abbot) on May 17, 2015 at 14:29 UTC | |
by BrowserUk (Patriarch) on May 17, 2015 at 15:07 UTC | |
by karlgoethebier (Abbot) on May 17, 2015 at 17:23 UTC |