Xin Cheng
Xin Cheng

Reputation: 91

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

Upvotes: 9

Views: 357

Answers (2)

mr_ron
mr_ron

Reputation: 479

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.

Upvotes: 7

Scimon Proctor
Scimon Proctor

Reputation: 4558

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;
        }
    }
}

Upvotes: 5

Related Questions