in reply to Threads From Hell #3: Missing Some Basic Prerequisites [Solved]
Finally, a version using shared variables ($r, $g, $b) provided by MCE::Shared to be released with MCE 1.7 supporting processes and threads. This completes in 8.743 seconds.
The fast option to MCE::Shared applies to deep data structures and okay to enable for this demonstration from not having circular references. Deep data sharing is fully automatic. Thus, one is not having to run shared_clone as in the previous post.
use strict; use warnings; use MCE::Flow; use MCE::Shared fast => 1; my $r = mce_share []; my $g = mce_share []; my $b = mce_share []; my ($m, $n, $count_max) = (500, 500, 2000); my ($x_max, $x_min, $y_max, $y_min) = ( 1.25, -2.25, 1.75, -1.75 ); #--------------------------------------------------------------------# # Perl version of Mandelbrot_OpenMP by John Burkardt. # http://people.sc.fsu.edu/~jburkardt/c_src/mandelbrot_openmp/ # mandelbrot_openmp.html # # Carry out the iteration for each pixel, determining count. sub mandelbrot { my ($m1, $m2) = @_; my ($x, $x1, $x2, $y, $y1, $y2); my ($c, %count, $i, $j, $k); for $i ( $m1 .. $m2 ) { for $j ( 0 .. $n - 1 ) { $x = ( ( $j - 1 ) * $x_max + ( $m - $j ) * $x_min ) / ( $m - 1 ); $y = ( ( $i - 1 ) * $y_max + ( $n - $i ) * $y_min ) / ( $n - 1 ); $count{$i}{$j} = 0; $x1 = $x; $y1 = $y; for $k ( 1 .. $count_max ) { $x2 = ( $x1 * $x1 ) - ( $y1 * $y1 ) + $x; $y2 = 2 * $x1 * $y1 + $y; if ( $x2 < -2.0 || 2.0 < $x2 || $y2 < -2.0 || 2.0 < $y2 ) { $count{$i}{$j} = $k; last; } $x1 = $x2; $y1 = $y2; } if ( ( $count{$i}{$j} % 2 ) == 1 ) { $r->[$i][$j] = 255; $g->[$i][$j] = 255; $b->[$i][$j] = 255; } else { $c = int( 255.0 * sqrt(sqrt(sqrt($count{$i}{$j} / $count_max))) ); $r->[$i][$j] = $g->[$i][$j] = 3 * $c / 5; $b->[$i][$j] = $c; } } } return; } #--------------------------------------------------------------------# # Return the smaller of two numbers. sub min { $_[0] < $_[1] ? $_[0] : $_[1]; } # Write image to an ASCII PPM file. sub write_to_ppm { my ($ofile) = @_; my ($FH, $i, $j, $jlo, $jhi); my $re = $r->export; # work is completed, okay to export my $ge = $g->export; my $be = $b->export; open $FH, '>', $ofile or die "cannot open file ($ofile): $!\n"; print $FH "P3\n"; print $FH "$n $m\n"; print $FH "255\n"; for ( $i = 0; $i < $m; $i++ ) { for ( $jlo = 0; $jlo < $n; $jlo += 4 ) { $jhi = min( $jlo + 4, $n ); for ( $j = $jlo; $j < $jhi; $j++ ) { printf $FH " %d %d %d", $re->[$i][$j], $ge->[$i][$j], $be->[$i][$j] } print $FH "\n"; } } close $FH; } #--------------------------------------------------------------------# # The bounds_only option applies to sequence of numbers # which means to compute the begin and end boundaries only, # not the numbers in between. Thus, workers receive 2 # numbers in @{ $chunk_ref }. # Same as mce_flow_s { mce options }, sub { ... }, 0, $m - 1; MCE::Flow::run_seq( { chunk_size => 5, max_workers => 'auto', bounds_only => 1 }, sub { my ($mce, $chunk_ref, $chunk_id) = @_; mandelbrot( @{ $chunk_ref} ); }, 0, $m - 1 ); # Write image to an ASCII PPM file. write_to_ppm('mandelbrot.ppm');
|
---|