2017-02-21 1 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

몇 가지 참고 사항은 대한 amet,elit.
ex.␤␤Donec.

이 : my @keys = $keysfilename.IO.words;

을이 : @keys.pick

나는 당신이 무슨 일을하는지 아주 확실하지 않다 : @keys[$len.rand.round] 그냥이 정말

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

그냥이 정말 카운터 배열, 그냥 0..99999 파일을 원하는 것처럼 것 같습니다.

각 스레드에 대한 서브 루틴 내에 잠금을 설정하고 있습니다. 여러 스레드가 무언가에 액세스하지 못하도록하려면 자물쇠 하나를 외부에 만들고 각각이 독점 코드를 잠그도록 사용하십시오.

또한 Thread을 사용하여 스레드를 만들었지 만 실제로는 매우 낮은 수준의 인터페이스 입니다. 가능한 경우 해당 레벨로 떨어지기 전에 상위 레벨 구조 인 을 사용하십시오.

이 경우, 일부 병렬 처리를 얻으려면 개의 파일을 여러 스레드로 분할하려는 것 같습니다. 거기에 은 정말 쉽게 만들 수있는 몇 가지 구성 요소입니다. 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

자물쇠 **는 ** 코드 외부에 있습니다. 그는 서브 루틴 람다 (subroutine lambda)를 사용하여 서브 루틴 클로저를 생성하고,'& getNext'를 그것에 설정했습니다. JavaScript로 어떻게해야하는지 생각합니다. 현대 Perl/Perl 6 방법은 그것들을'state' 변수로 선언하는 것입니다. –

+0

맞습니다. 코드를 따르는 데 어려움을 겪고있었습니다. 감사. –

+0

@CurtTilmes 감사합니다. 프로그램의 각 라인을 이해합니다.))) –

8

Threads을 Perl 6에서 직접 사용해야하는 이유는 거의 없습니다. 바로 당신을 위해 많은 기능을 제공합니다. 대부분의 경우 가장 간단한 개선은 Thread.start 대신 start을 사용하고 LIST».join 또는 LIST.map(*.join) 대신 await LIST을 사용하는 것입니다.

List.join이 아니고 Thread.join이 아니며 적어도 부분적으로 문제가있는 것일 수 있습니다.

이 내용을 읽고 이해하기가 더욱 어려워집니다.


어떻게 작성했는지 getNext 당신이 알고있는 것 또는 대부분 JavaScript 만있는 것 같습니다. 이것이 내가 그것을 쓰는 방법이다.

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

만 매개 변수의 기본 읽기 전용 의미를 무시할 수 @filename을 사용하는 것을 제외하고.

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 개선 할 수있는 방법을 보여 주었다, 나는 그것을 멀리 던져 펄 6 훨씬 좋네요 기능을 사용하는거야.

# 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(' '); 
} 

(이 방법에 의해 Channel을 사용하는 것이 더 의미 만들었을 것입니다) (I 테스트를 실행, 그리고 그것은 스레드 ID보다 높은 6 준 적이) 내가 사용


을 반환 값은 어쨌든 버려지기 때문에 hyper 대신 race이됩니다.

작동하지 않는 경우, Rakudo 버전이 있습니다. 그래서 최신 버전의 v2017.02
(say $*PERL.compiler.version;)에 업데이트를 추천 할 것입니다 경우


[email protected]

^ NUMBER

Range.new(0, NUMBER, :excludes-max) 
설탕 인 0 ..^ NUMBER과 동일 @array.elems과 동일

이것은 여전히 ​​유용합니다. 일부 "단어"에는 여분의 문자가 있습니다. 예를

… 

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이 고려해야 할 니트 및/또는 다른 사람들이 읽는 노트입니다. Brad는 내부 for'(for'for 'pos ...')에 함축적 인 "it"변수 ('$ _')를 의지했다. 그는 바깥 쪽'for '('race ...')에서'-> $ counter' 비트를 놓고 똑같은 일을 할 수있었습니다. $'THREAD '는'say '라인을 단순화하기 위해 $ counter를 썼을 수도있다. 그는'@ keys.roll'보다는'@ keys.pick (1)'을 쓸 수있었습니다. 필자는'spurt' 라인을 사용하여 추악함과 OS 특이성 ('$ * SPEC'은 OS/플랫폼 고유의 IO 코드를 나타냄)을 포장하고있다. – raiph

+0

성능상의 이유로'-'{'이 아니라'-'{'를 쓰면 암시적인'$ _?'을 일부 블록 서명에서 제거하고 있습니까? – raiph

+1

@raiph 필자는'.pick()'대신'.roll()'을 사용하여 누군가가 같은 값을 두 번 이상 롤백 할 수 있다는 것을 깨달을 수 있도록했습니다. (나는 처음부터'.pick'을 호출 할 때마다 처음부터 시작한다는 것을 깨닫지 못했던 한 사람을 만났습니다.)'-> {는 불필요하며 새로운 Perl 6 프로그래머가 그것을 깨닫게 할 수 있도록 추가되었습니다. 매개 변수 없음을 나타냅니다. 그 밖의 모든 것은 질문의 코드를 모방하여 여기에서 어떻게 도달 할 수 있는지를 확인하는 것이 었습니다. –