2017-02-21 7 views
3

$keysfilenameファイルに格納されたキーで3つの単語を置換した "ランダム"テキストファイルを生成するプログラムを作成します。私は複数のスレッドを使用する場合Perl6マルチスレッドスパートの問題

ASD123ASD 
QWE123QWE 
XZC123ZXC 

問題がエラー

started 
Thread<17>(14) got 1 
Thread<18>(15) got 2 
Thread<20>(17) got 17 
Thread<5>(2) got 3 
Thread<16>(13) got 4 
Thread<21>(18) got 5 
Thread<3>(0) got 6 
Thread<8>(5) got 7 
Thread<12>(9) got 10 
Thread<11>(8) got 8 
Thread<9>(6) got 9 
Thread<14>(11) got 11 
Thread<15>(12) got 12 
Unhandled exception: Failed to open file C:\c\perltests\00000017.txt: no such file or directory 
Thread<10>(7) got 13 
Thread<13>(10) got 14 
Thread<7>(4) got 15 
Thread<19>(16) got 16 
Thread<4>(1) got 0 
Thread<6>(3) got 18 
Thread<22>(19) got 19 
    at <unknown>:1 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:throw:4294967295) 
Thread<23>(20) got 20 
Thread<24>(21) got 21 
from gen/moar/m-CORE.setting:22337 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:throw:34) 
Thread<26>(23) got 22 
Thread<25>(22) got 23 
Thread<27>(24) got 24 
from gen/moar/m-CORE.setting:22374 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:FALLBACK:35) 
Thread<28>(25) got 25 
Thread<29>(26) got 26 
from gen/moar/m-Metamodel.nqp:3041 (C:\rakudo\share\nqp\lib/Perl6/Metamodel.moarvm::13) 
Thread<30>(27) got 27 
Thread<16>(13) got 28 
Thread<17>(14) got 29 
Thread<5>(2) got 30 
Thread<18>(15) got 31 
Thread<14>(11) got 32 
Thread<15>(12) got 33 
from gen/moar/m-CORE.setting:25189 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:226) 
Thread<30>(27) got 58 
Thread<29>(26) got 57 
Unhandled exception: Failed to open file C:\c\perltests\00000028.txt: no such file or directory 
Thread<28>(25) got 56 
from gen/moar/m-CORE.setting:25203 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:92) 
Thread<25>(22) got 55 
from gen/moar/m-CORE.setting:25199 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:44) 
Thread<27>(24) got 54 
from gen/moar/m-CORE.setting:25506 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:96) 
Thread<26>(23) got 53 
from gentexts.pl:54 (<ephemeral file>::189) 
Thread<24>(21) got 52 
Thread<23>(20) got 51 
Unhandled exception: Failed to open file C:\c\perltests\00000058.txt: no such file or directory 
Thread<6>(3) got 50 
Thread<22>(19) got 49 
    at <unknown>:1 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:throw:4294967295) 
Thread<34>(31) got 48 
from gen/moar/m-CORE.setting:22337 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:throw:34) 
Thread<33>(30) got 47 
Thread<4>(1) got 46 
from gen/moar/m-CORE.setting:22374 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:FALLBACK:35) 
Thread<7>(4) got 45 
from gen/moar/m-Metamodel.nqp:3041 (C:\rakudo\share\nqp\lib/Perl6/Metamodel.moarvm::13) 
Thread<19>(16) got 44 
Thread<11>(8) got 43 
    at <unknown>:1 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:throw:4294967295) 
Thread<8>(5) got 42 
from gen/moar/m-CORE.setting:22337 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:throw:34) 
Thread<12>(9) got 41 
Thread<10>(7) got 40 
from gen/moar/m-CORE.setting:25189 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:226) 
Thread<13>(10) got 39 
from gen/moar/m-CORE.setting:25203 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:92) 
Thread<31>(28) got 37 
from gen/moar/m-CORE.setting:25199 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:44) 
Thread<32>(29) got 38 
Thread<9>(6) got 36 
from gentexts.pl:44 (<ephemeral file>::15) 
Thread<3>(0) got 35 
Thread<21>(18) got 34 
from gen/moar/m-CORE.setting:22374 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:FALLBACK:35) 
Thread<17>(14) got 59 
from gen/moar/m-CORE.setting:25506 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:spurt:96) 
Thread<5>(2) got 60 
Thread<18>(15) got 61 
from gentexts.pl:54 (<ephemeral file>::189) 
Thread<9>(6) got 85 
Thread<32>(29) got 84 
from gen/moar/m-CORE.setting:30638 (C:\rakudo/share/perl6/runtime/CORE.setting.moarvm:THREAD-ENTRY:44) 

システムで、たとえば

my @threads = (^32).map({ 

任意のファイルに失敗した場合のために、起こるようにキーファイルは、非常にシンプルな構造を持っていますWin 10 x32、Rakudo 6.c

my $keysfilename := 'C:/c/keysfile.txt'; 
my $output  := 'C:/c/perltests'; 

my @keys =(); 
for $keysfilename.IO.words { 
    @keys.push($_); 
} 
my $len := elems @keys; 

my $lorem = q:to/END/; 
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec malesuada purus vel tincidunt eleifend. Fusce sollicitudin augue augue, et gravida dolor varius a. Vestibulum iaculis, dui iaculis iaculis molestie, tellus ante hendrerit massa, at volutpat risus metus vitae nisi. Integer neque magna, ultrices eu erat at, efficitur sollicitudin sem. Aliquam sed purus malesuada, porta est eu, rutrum neque. Quisque dolor leo, condimentum non mollis eget, tristique eget odio. Donec dignissim magna nec imperdiet iaculis. Vestibulum lorem ligula, euismod ac porttitor faucibus, rutrum eu ex. 

Donec scelerisque nisi eget risus condimentum ultrices. Integer porta maximus quam, in lobortis quam fermentum eu. Morbi eu ligula consequat, aliquam sem eget, sollicitudin eros. Suspendisse potenti. Cras finibus metus et eros accumsan, id vehicula libero lobortis. Aenean vulputate lacinia urna at fringilla. Nulla id tincidunt lectus, quis accumsan lorem. In posuere magna non purus hendrerit rutrum. Maecenas in mattis tellus. Maecenas vel feugiat enim. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin convallis dapibus tellus vitae euismod. Nam eleifend dui quam, eget lobortis quam pulvinar id. Cras euismod posuere dolor non ultricies. 

Ut dapibus porta faucibus. Duis velit ante, tincidunt id velit id, imperdiet egestas velit. Morbi efficitur enim dignissim interdum egestas. Vivamus eu urna condimentum, aliquam orci non, ullamcorper est. Phasellus egestas at tellus nec tristique. Fusce feugiat commodo faucibus. In hac habitasse platea dictumst. Quisque dignissim, mauris a pellentesque dictum, mauris velit tincidunt lorem, sed tincidunt libero enim vitae orci. Nam interdum, ante nec consequat vulputate, nisi turpis euismod nibh, sit amet elementum nunc diam non eros. Proin quis viverra risus. Vestibulum vestibulum diam in velit consectetur, eu elementum lacus sagittis. Morbi accumsan ac ante eget faucibus. In nec elit bibendum, tristique enim non, sodales ex. Donec sodales erat vitae odio cursus commodo. 

Vestibulum felis lacus, mattis eget porta eget, mattis ut felis. Pellentesque aliquet, purus eu semper suscipit, sem ipsum euismod nunc, sed dapibus augue sem vel elit. Etiam tincidunt arcu ut nisi tempor commodo. Mauris at eros tincidunt, fringilla erat nec, sagittis ante. Integer et malesuada quam. Cras vel porta erat, sit amet efficitur erat. Praesent blandit purus quis urna consectetur, eget ultricies ipsum pulvinar. Phasellus ac molestie elit. Vestibulum et tincidunt velit. Aliquam a venenatis ipsum, nec commodo libero. Nullam eget consectetur lectus. Morbi placerat interdum erat nec interdum. 

Morbi bibendum dui eu turpis pretium, eget aliquet augue aliquam. Aliquam eu dignissim mauris, vitae placerat augue. Ut sed tortor sit amet augue imperdiet rutrum. Aliquam erat volutpat. Morbi a turpis in sapien ultrices tristique. Proin quis vestibulum lorem, ut pharetra ex. Quisque tempor bibendum purus ac vehicula. Suspendisse tellus ipsum, imperdiet id sodales vel, congue a leo. Nulla gravida tincidunt nisi eu tempor. Mauris imperdiet tempor ante eget rutrum. Nam ut dui at augue laoreet mollis. Sed metus elit, viverra ac fringilla vel, fermentum et magna. Nam ligula purus, pretium vel dignissim vitae, fermentum at urna. Nullam ac ullamcorper felis. Maecenas dapibus consequat mi. 
END 

my @words = $lorem.split(' '); 
my $wordlen = @words.elems; 

my &getNext = sub { 
    my $counter = 0; 
    my Lock $lock .= new; 
    return sub (@filename) { 
     $lock.lock; 
     if ($counter < 100_000) { 
      @filename[0] = $counter; 
      $counter++; 
     } 
     $lock.unlock; 
    }; 
}(); 

say "started"; 

my @threads = (^1).map({ 
    Thread.start(
     name => $_, 
     sub { 
      loop {    
       my @counter = (-1); 
       getNext(@counter); 
       last if @counter[0] < 0; 
       say $*THREAD ~ " got " ~ @counter[0]; 
       my @copy = @words.clone; 
       for (^3) { 
        my $pos = $wordlen.rand.round; 
        @copy[$pos] = @keys[$len.rand.round]; 
       } 
       spurt sprintf($output ~ '/%08d.txt', @counter[0]), @copy.join(' '); 
      } 
     } 
    ); 
}).join; 

答えて

9

いくつかの注意事項。

この:

my @keys =(); 
for $keysfilename.IO.words { 
    @keys.push($_); 
} 

は本当にただ、このされていますmy @keys = $keysfilename.IO.words;

と、この:@keys[$len.rand.round] は本当にただこれです:@keys.pick

私はあなたがやっていることは非常にわからないんだけどカウンターアレイ、0..99999が好きなように のようです。

スレッドごとにサブルーチン内にロックを作成しています。 複数のスレッドが何かにアクセスしないようにしたい場合は、ロックを の外に1つ作成し、それぞれに専用のコードをロックするようにしてください。

また、Threadを使用してスレッドを作成していますが、それは実際にはかなり低いレベルのインターフェイス です。可能であれば、そのレベルに落ちる前に、より高いレベルの構造体 を使用してください。

この場合、いくつかの並列性を得るために、100000個のファイル を複数のスレッドに分割したいと思うようです。そこに は、それを本当に簡単にするいくつかの構成です、hyperraceです。あなたはファイルがどのような順序で作成されているか気にしないので、あなたはレースを使用することができ、できるだけ速く としてそれらを整理します。

「degree」パラメータをraceに設定すると、使用するスレッドの数を とすることができます。(RAKUDO_MAX_THREADSを に設定する必要があるかもしれません)。

my $keysfilename := 'C:/c/keysfile.txt'; 
my $output  := 'C:/c/perltests'; 

my @keys = $keysfilename.IO.words; 

my $lorem = q:to/END/; 
Lorem ipsum ... 
END 

my @words = $lorem.split(' '); 
my $wordlen = @words.elems; 

[^100000].race(degree => 32).map({ 
# say $*THREAD ~ " got " ~ $_; 

    my @copy = @words; 

    for (^3) { 
     my $pos = $wordlen.rand.round; 
     @copy[$pos] = @keys.pick; 
    } 

    spurt sprintf($output ~ '/%08d.txt', $_), @copy.join(' '); 
}); 
+0

ロック**は**コード外です。彼はサブルーチンラムダを使ってサブルーチンクロージャを作成し、それに '&getNext'を設定しました。 JavaScriptでどのようにしなければならないかと思います。現代のPerl/Perl 6の方法は、それらを 'state'変数として宣言することです。 –

+0

あなたが正しいです - 私はコードに続く問題を抱えていました。ありがとう。 –

+0

@CurtTilmesありがとう、私はあなたのプログラムの各ラインを理解している))) –

8

ThreadsをPerl 6で直接使用する理由はほとんどありません。あなたにとっては沢山の機能があります。ほとんどの場合、最も簡単な改善は、の代わりにstartを使用し、LIST».joinまたはLIST.map(*.join)の代わりにawait LISTを使用することです。

List.joinThread.joinではありません。少なくとも部分的に問題が発生している可能性があります。

これを読みにくく理解することがさらに多くのことがあります。


投稿者の投稿getNextあなたはほんの一部、またはほとんどJavaScriptのみを知っているようです。これは私がそれを書く方法です。あなただけのパラメータのデフォルトの読み取り専用セマンティクスをバイパスする@filenameを使用していることを除いて

sub get-next (@filename) { 
    state Int $counter = 0; # set to zero only the first time it is called 
    state Lock $lock .= new; 

    $lock.protect: ->{ 
     if $counter < 100_000 { 
      @filename[0] = $counter++; 
     } 
    } 
} 

sub get-next ($filename is rw) { 
    state Int $counter = 0; 
    state Lock $lock .= new; 

    $lock.protect: ->{ 
     if $counter < 100_000 { 
      $filename = $counter++; 
     } 
    } 
} 

を除いて、値を返すほうが意味があります。

sub get-next() { 
    state Int $counter = 0; 
    state Lock $lock .= new; 

    $lock.protect: ->{ 
     $counter++ if $counter < 100_000 
    } // Nil 
    # the `if` will return `Empty` when $counter gets too big 
    # but we want `Nil` instead 
} 

このどちらかは、あなたがこのようにそれを使用できるように未定義の値がカウンターまたはNilを返します。

loop { 
    my $counter = get-next() orelse last; 
    … 
} 

あなただけの今までのループでサブを使用しているので、それができましたちょうどlastを呼び出してください。
いっそあなたの代わりに、あなたはどこにでもlastを追加する必要はありませんし、whileループにloopを変えることができる

state Int $counter = 0 but True; 

にカウンタを宣言した行を変更した場合。

while get-next() -> $counter { … } 

今、私はあなたがgetNext向上させることができますどのようにあなたを示したことが、私はそれを捨てるとPerl 6の非常に良く機能を使用するつもりです。
(それは仕方によってChannelを使用する方が理にかなっているだろう)

# will probably still work with `use v6.c;` 
# but v6.d has a better system backing `await` 
use v6.d.PREVIEW; 

# override the original default number of threads 
# (16 threads currently) 
BEGIN %*ENV<RAKUDO_MAX_THREADS> //= 32; 
# the "correct" way to do this is setting $*SCHEDULER 
# but this is easier 

my $keys-filename = 'C:/c/keysfile.txt'; 
my $output-dir = 'C:/c/perltests'; 

my @keys = $keys-filename.IO.words; 

my @lorem = q:to/EOF/.split(' '); 
… 
EOF 

say 'started'; 
END say 'finished'; 

for race ^100_000 -> $counter { 
    say $*THREAD, " got ", $counter; 
    my @copy = @lorem; # no need for .clone 

    for (^[email protected]).pick(3) -> $pos { 
     @copy[$pos] = @keys.roll; 
    } 

    spurt $*SPEC.catfile($output-dir, $counter.fmt('/%08d.txt')), @copy.join(' '); 
} 

(私はテストを実行し、それが6より高いスレッドIDを与えたことはない)


私が使用しましたとにかく戻り値が破棄されるため、hyperではなくraceとなります。

うまくいかなかった場合は、かわいいバージョンのRakudoがあります。もしそうなら、私は


[email protected]最新のリリースv2017.02
say $*PERL.compiler.version;)へのアップデートをお勧めします@array.elems

^ NUMBER

Range.new(0, NUMBER, :excludes-max) 
ための砂糖である 0 ..^ NUMBERと同じであるのと同じです

これにはまだ手続きがあります「単語」の中には余分な文字があるものがあります。
amet,例えばelit.ex.␤␤Donec

… 

my @pos = ($lorem ~~ m:ex/ « \w+: /).map: { .from, .chars } 
# @pos looks something like [(0,5),(6,5),(12,5),(18,3),…] 

… 

for race ^100_000 -> $counter { 
    say $*THREAD, " got ", $counter; 

    # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 
    my $copy = $lorem; 

    # sort so that the transforms are done from the end of the string 
    # towards the beginning of the string 
    for @pos.pick(3).sort.reverse { 
     $copy.substr-rw(|$_) = @keys.roll; 
    } 
    # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

    spurt $*SPEC.catfile($output-dir, $counter.fmt('/%08d.txt')), $copy; 
} 
+1

偉大な答え。以下は、ブラッドが考慮する姪、および/または他の人が読んでいるノートです。 Bradは内側の 'for'(' for @pos ... ')の暗黙の" it "変数(' $ _')に依存していました。彼は ' - > $ counter'ビットを落として外側の 'for'(' for race ... ')と同じことをすることができました。彼は、 'say 'という行を簡略化するため$ $' 'をつけたと言ってもいいかもしれません(' $ counter'を落としたと仮定します)。彼は '@ keys.roll'ではなく' @ keys.pick(1) 'を書くことができました。私は '' spurt'行を使って醜さとOS特化をパッケージ化するルーチンを書いています( '$ * SPEC'はOS /プラットフォーム固有のIOコードを示します)。 – raiph

+0

パフォーマンス上の理由から ' - ' {'ではなく' - '{'を書くことで、暗黙の '$ _?'をいくつかのブロック署名から削除していますか? – raiph

+1

@raiph私は '.pick()'ではなく '.roll()'を特に使っていました。 (私はあなたが '.pick'を呼び出すたびに最初から始まると気付かなかった一人の人に出くわしました)' - > {は不要で、新しいPerl 6プログラマーがパラメータがないことを示します。他のすべては質問のコードを模倣し、ここからそこに到達する方法を見ることが可能です。 –

関連する問題