ちなみにGaucheの遅延シーケンスはスレッドセーフで、複数のスレッドが同時に頭から素数を取って行っても安全です。こちらの実装はどうですか? (挑戦状)
shiro - 2011/10/02 12:09
ちょっと調べてみた感じでは、Squeak のジェネレーターでスレッドセーフは考慮されていないようです。残念。
実際、複数のスレッドからアクセスすると #next で素数ではなく変なもの(コンテキスト)が戻ってくることがあり、正しい答えを返せなくなります。
| primesGen queue | primesGen := Generator on: [:g | | primes next | primes := OrderedCollection withAll: #(2 3 5 7). primes do: [:prime | g value: (next := prime)]. [ [:exit | [ next := next + 2. primes anySatisfy: [:prime | prime * prime > next ifTrue: [exit value]. next isDivisibleBy: prime] ] whileTrue] valueWithExit. g value: (primes add: next) ] repeat]. queue := SharedQueue2 new. 100 timesRepeat: [ [50 timesRepeat: [ queue nextPut: primesGen next -> Processor activeProcess name. Processor yield] ] fork]. 5000 timesRepeat: [result := queue next key]. result "=> 47533 "
Generator>>#next を排他的にしてしまえば改善するはずなので試してみましょう。
Stream subclass: #Generator
instanceVariableNames: 'block next continue home monitor'
Generator >> initializeOn: aBlock
monitor := Monitor new.
block := aBlock.
self reset
Generator >> next
"Generate and answer the next object in the receiver."
^ monitor critical: [
self atEnd ifFalse: [
home swapSender: thisContext sender.
continue := thisContext swapSender: continue
].
monitor signal]
]
とりあえずこれで正しい答えは返せるようになりました。
| primesGen queue | "略" queue := SharedQueue2 new. 100 timesRepeat: [ [50 timesRepeat: [ queue nextPut: primesGen next -> Processor activeProcess name. Processor yield] ] fork]. 5000 timesRepeat: [result := queue next key]. result "=> 48611 "
速度面での影響もさほどはないようです。
| primesGen result | "略" {[5000 timesRepeat: [result := primesGen next]] timeToRun. result} "=> #(41 48611) "