Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl6 grep like program in parallel

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

like image 889
Xin Cheng Avatar asked Jun 29 '18 00:06

Xin Cheng


2 Answers

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.

like image 63
mr_ron Avatar answered Sep 22 '22 14:09

mr_ron


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;
        }
    }
}
like image 29
Scimon Proctor Avatar answered Sep 25 '22 14:09

Scimon Proctor