in reply to Risque Romantic Rosetta Roman Race
I combined reading, processing, and output into a small chunking routine utilizing MCE. The parallel Perl code may run faster than C, depending on the number of logical CPU cores. This includes tybalt89's optimization.
# rtoa-pgatram-mce.pl # Example run: perl rtoa-pgatram-mce.pl t1.txt >mce.tmp # # Convert a "modern" Roman Numeral to its arabic (decimal) equivalent. # The alpabetic input string may be assumed to always contain a valid +Roman Numeral in the range 1-3999. # Roman numerals may be upper or lower case. # Error handling is not required. # For example: # input "XLII" should produce the arabic (decimal) value 42 # input "mi" should produce the arabic (decimal) value 1001 use strict; use warnings; use List::Util qw(reduce); use Time::HiRes qw(time); use MCE; # Function roman_to_arabic # Output a list of their arabic (decimal) values to standard output. # sub roman_to_arabic { my $files = shift; # in: reference to a list of files containin +g Roman Numerals (one per line) my %rtoa = ( M=>1000, D=>500, C=>100, L=>50, X=>10, V=>5, I=>1 ); # construct a pool of workers my $mce = MCE->new( max_workers => MCE::Util::get_ncpu(), chunk_size => 90 * 1024, init_relay => 1, # if defined, tells MCE to load MCE::Relay p +lus extra setup posix_exit => 1, user_func => sub { my ( $mce, $chunk_ref, $chunk_id, $output ) = ( @_, '' ); chomp @{$chunk_ref}; for ( @{$chunk_ref} ) { # $output .= reduce { $a+$b-$a%$b*2 } map { $rtoa{$_} } spli +t //, uc($_); $output .= reduce { $a+$b-$a%$b*2 } @rtoa{ split //, uc($_ +) }; $output .= "\n"; } # output orderly MCE::relay { print $output }; } ); # process a list of files for my $fname ( @{$files} ) { warn("$0: cannot access '$fname': No such file or directory\n"), + next unless -e $fname; warn("$0: cannot access '$fname': Permission denied\n"), next unless -r $fname; warn("$0: cannot process '$fname': Is a directory\n"), next if -d $fname; $mce->process({ input_data => $fname }); } # reap MCE workers $mce->shutdown; } @ARGV or die "usage: $0 file...\n"; my @rtoa_files = @ARGV; warn "rtoa pgatram start\n"; my $tstart = time; roman_to_arabic(\@rtoa_files); warn sprintf("time %0.03f secs\n", time - $tstart);
I updated rtoa-pgatram.pl to include the same optimization. What I find interesting is the time difference compared to real time for the C demonstration. The delta time is likely global cleanup. Parallelization involved running on physical and logical CPU cores via the taskset utility. Hence, the reason not seeing 8x comparing one thread and eight threads. For reference, running on eight physical cores completed in 0.814 seconds (7.2x).
$ time ./rtoa-pgatram t1.txt >cpp.tmp read_input_file : 3999000 items read file time : 0.136 secs roman_to_dec time : 0.116 secs output time : 0.187 secs real 0m0.450s user 0m0.416s sys 0m0.034s $ time perl rtoa-pgatram.pl t1.txt >pgatram.tmp rtoa pgatram start read_input_files : 1 secs roman_to_arabic : 4 secs output : 1 secs total : 6 secs real 0m6.259s user 0m6.131s sys 0m0.128s $ time perl rtoa-pgatram-mce.pl t1.txt >mce.tmp rtoa pgatram start time 1 thread : 5.808 secs time 8 threads : 1.151 secs ( 5.05x) time 16 threads : 0.643 secs ( 9.03x) time 32 threads : 0.347 secs (16.74x) time 64 threads : 0.225 secs (25.81x) 1 thd 8 thds 16 thds 32 thds 64 thds real 0m5.835s 0m1.178s 0m0.671s 0m0.375s 0m0.252s user 0m5.832s 0m9.064s 0m8.874s 0m8.935s 0m9.698s sys 0m0.008s 0m0.024s 0m0.030s 0m0.073s 0m0.136s
Thank you, for the interesting series. This allowed me to practice using MCE.
$ cksum cpp.tmp pgatram.tmp mce.tmp 1397892467 18888000 cpp.tmp 1397892467 18888000 pgatram.tmp 1397892467 18888000 mce.tmp
|
---|