I wrote a grep-like program in perl6, and now I made it into parallel processing. But I ran into some problem: even with the same command line the program sometimes succeeds, and sometimes fails. When it succeeds, things looks just normal to me. When it fails, I don't know why...
Here is the error message when it fails.
> grep6 perl *
An operation first awaited:
in sub MAIN at /Users/xxx/Dropbox/bin/grep6 line 28
in block <unit> at /Users/xxx/Dropbox/bin/grep6 line 30
Died with the exception:
Cannot find method 'Any' on object of type Match
in regex at /Users/xxx/Dropbox/bin/grep6 line 34
in sub do_something at /Users/xxx/Dropbox/bin/grep6 line 34
in block at /Users/xxx/Dropbox/bin/grep6 line 24
And the code is:
#!/usr/bin/env perl6
constant $color_red = "\e[31m";
constant $color_off = "\e[0m";
sub MAIN(Str $pattern, *@filenames){
my $channel = Channel.new();
$channel.send($_) for @filenames; # dir();
$channel.close;
my @workers;
for 1..3 -> $n {
push @workers, start {
while (my $file = $channel.poll) {
do_something($pattern, $file);
}
}
}
await(@workers);
}
sub do_something(Str $pattern, Str $filename) {
#say $filename;
for $filename.IO.lines -> $line {
my Str $temp = $line;
if $temp ~~ s:g/ (<$pattern>) /$color_red$0$color_off/ {
say $filename ~ ": " ~ $temp;
}
}
}
My question is why it fails sometimes?
Regards
Xin
This problem seems to be basically the same as a known rakudo issue for the race
method.
I switched from:
if $temp ~~ s:g/ (<$pattern>) /$color_red$0$color_off/ {
to:
if $temp ~~ s:g/ ($pattern) /$color_red$0$color_off/ {
and the problem seemed to go away.
As later mentioned by Xin Cheng and also described in the same doc, the simpler interpolation matches literally as clarified by the doc examples. The issue ticket fixed the problem with something like:
my $reg = regex { <$pattern> };
'' ~~ $reg;
leading to an updated program with a similar workaround:
#!/usr/bin/env perl6
constant $color_red = "\e[31m";
constant $color_off = "\e[0m";
sub MAIN(Str $pattern, *@filenames){
my $channel = Channel.new();
$channel.send($_) for @filenames; # dir();
$channel.close;
my @workers;
# match seems required for pre-compilation
'' ~~ (my regex pat_regex { <$pattern> });
for 1..3 -> $n {
push @workers, start {
while (my $file = $channel.poll) {
do_something(&pat_regex, $file);
}
}
}
await(@workers);
}
sub do_something(Regex $pat_regex, Str $filename) {
# say $filename;
for $filename.IO.lines -> $line {
my Str $temp = $line;
if $temp ~~ s:g/ ($pat_regex) /$color_red$0$color_off/ {
say $filename ~ ": " ~ $temp;
}
}
}
My apologies for the earlier proposed explicit EVAL
solution, about which the best I can say is that my description requested a better solution.
Did a bit of playing about the issue seems to be the anonymous regexp you're creating by doing :
s:g/ (<$pattern>) /$color_red$0$color_off/
If you instead precompile your regex (either in do_something
or the MAIN
routine then the errors stop.
Here's the updated do_something
version :
sub do_something(Str $pattern, Str $filename) {
my $reg = regex { $pattern };
for $filename.IO.lines -> $line {
my Str $temp = $line;
if $temp ~~ s:g/ ($reg) /$color_red$0$color_off/ {
say $filename ~ ": " ~ $temp;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With