Skip to content

Instantly share code, notes, and snippets.

@MadcapJake
Last active May 7, 2016 22:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MadcapJake/c29b76d7eccf5af86e973c5da7c7f7a3 to your computer and use it in GitHub Desktop.
Save MadcapJake/c29b76d7eccf5af86e973c5da7c7f7a3 to your computer and use it in GitHub Desktop.
Shakespeare Counter
my $text = open 'test.txt';
constant CHUNK_SIZE = 5;
constant Vowels = <a e i o u A E I O U>.Set;
constant Consonants = <B C D F G H J K L M N P Q R S T V W X Y Z b c d f g h j k l m n p q r s t v w x y z>.Set;
sub channeled {
my ($read, $parsed) = Channel.new xx 2;
reader($text, $read);
counter($read, $parsed);
my @all-counts = await combiner($parsed);
@all-counts».say;
}
sub reader($text, Channel $dest) {
start {
CATCH { $dest.fail($_) }
my @chunk;
for $text.lines {
if @chunk.elems < CHUNK_SIZE { @chunk.push($_) }
else { $dest.send(@chunk.join("\n")); @chunk = Empty }
}
$dest.close
}
}
sub counter(Channel $source, Channel $dest) {
await gather for $source.list -> $chunk {
$chunk.say;
take start {
CATCH { $dest.fail($_) }
my int @ic = (0, 0, 0);
for $chunk.comb -> $_ {
when $_ ∈ Vowels { @ic[0]++ }
when $_ ∈ Consonants { @ic[1]++ }
default { @ic[2]++ }
}
$dest.send(@ic)
}
}
$dest.close
}
sub combiner(Channel $source) {
my Promise $promise .= new;
my $vow = $promise.vow;
start {
CATCH { $vow.break($_) }
my int @result = (0, 0, 0);
@result «+=» $_ for $source.list;
$vow.keep(@result)
}
$promise
}
channeled()
my $text = open 'shakespeare.txt';
class Counter {
has $.name;
has int $!count = 0;
method tick { $!count++ }
method gist { "Counter.new(name => $!name, count => $!count)" }
}
sub naive {
my ($vowel, $consonant, $other) = do Counter.new(:name($_)) for <vowel consonant other>;
my \vowels = <a e i o u A E I O U>.Set;
while ($_ = $text.getc) {
when $_ ∈ vowels { $vowel.tick }
when /<:Letter>/ { $consonant.tick }
default { $other.tick }
}
($vowel, $consonant, $other)».say
}
naive(); #={214.14user 0.04system 3:34.14elapsed 100%CPU}
constant CORES = 6;
constant Vowels = <a e i o u A E I O U>.Set;
constant Consonants = <B C D F G H J K L M N P Q R S T V W X Y Z b c d f g h j k l m n p q r s t v w x y z>.Set;
my $text = open 'test.txt', :r;
class Worker {
has Channel $.chunks .= new;
has Channel $!collector;
has Bool $.done = False;
method new ($collector) { self.bless(:$collector) }
submethod BUILD(:$!collector) {
start {
CATCH { $!chunks.fail($_) }
loop {
if $!chunks.poll -> $chunk {
'WORKER: poll'.say;
my int @a = 0, 0, 0;
for $chunk.comb -> $_ {
when $_ (elem) Vowels { @a[0]++ }
when $_ (elem) Consonants { @a[1]++ }
default { @a[2]++ }
}
$!collector.send(@a);
} elsif $!chunks.closed { $!done = True; last }
}
}
}
}
sub employer {
my ($provider, $collector) = Channel.new xx 2;
my Worker @workers = Worker.new($collector) xx CORES;
my int @collected = 0, 0, 0;
start { # Give chunks to provider for divying up
CATCH { $provider.fail($_) }
$provider.send($_) for $text.lines; #.rotor(20)».join("\n");
$provider.close
}
start { # provide chunks to each worker
my $cursor = 0;
loop {
if $provider.poll -> $chunk {
'PROVIDE: poll'.say;
@workers[$cursor].chunks.send($chunk);
$cursor = 0 if ++$cursor == CORES
} elsif $provider.closed { last }
}
@workers».chunks».close;
loop { if all @workers».done { $collector.close; last } }
}
return await start { # apply the worker's ticks to @collected
CATCH { $collector.fail($_) }
loop {
if $collector.poll -> @ticks {
"COLLECT: @ticks[] into @collected[]".say;
@collected «+=» @ticks
}
elsif $collector.closed { last }
}
@collected
}
}
employer();
@timo
Copy link

timo commented May 7, 2016

#!/usr/bin/env perl6

my $fh = open 't8.shakespeare.txt',:r;

constant Vowels = <a e i o u A E I O U>.Set;
constant Consonants = <B C D F G H J K L M N P Q R S T V W X Y Z b c d f g h j k l m n p q r s t v w x y z>.Set;

my $input-channel = Channel.new;

my @counter-workers = do for ^4 {
    start {
        my int @values = 0, 0, 0;
        for $input-channel.list {
            for .comb -> $char {
                if $char (elem) Vowels {
                    @values[0]++;
                } elsif $char (elem) Consonants {
                    @values[1]++;
                } else {
                    @values[2]++;
                }
            }
        }
        @values;
    }
}

$input-channel.send($_) for $fh.lines;
$input-channel.close;

my @partials = await @counter-workers;

say ([Z+] @partials).perl;

@timo
Copy link

timo commented May 7, 2016

my $text = open 't8.shakespeare.txt', :r;

class Counter {
    has $.name;
    has int $!count = 0;
    method tick { $!count++ }
    method gist { "Counter.new(name => $!name, count => $!count)" }
}

sub naive {
    my ($vowel, $consonant, $other) = do Counter.new(:name($_)) for <vowel consonant other>;
    my \vowels = <a e i o u A E I O U>.Set;
    my \consonants = <B C D F G H J K L M N P Q R S T V W X Y Z b c d f g h j k l m n p q r s t v w x y z>.Set;
    while ($_ = $text.getc) {
        if $_ (elem) vowels { $vowel.tick }
        elsif $_ (elem) consonants { $consonant.tick }
        else { $other.tick }
    }
    ($vowel, $consonant, $other)».say
}
naive();

this version is significantly faster than the one in your gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment