From: sinara@... Date: 2002-04-22T22:08:18+09:00 Subject: [ruby-list:34956] Re: Thread by callcc 原です。 In message "[ruby-list:34952] Re: Thread by callcc" on 02/04/21, Tanaka Akira writes: >だとしたら、むしろスレッドの亜種としてコルーチンのサポートを入れるとい >う手もあるのでは? > >と、思ったので、試してみました。 なるほど、Thread でもできるとは思っていたのですが、面白いですね。 Coroutine は、2つのスレッドでのピンポン方式ですね。 >--- sync-each.rb --- >require 'coroutine' SyncEach はピンポンでする方法もあるのか、、、この方式の CoThread 版を書いておきます。 ---^ sync-each2.rb require "co-thread-queue" class SyncEach include Enumerable def initialize(*es) @size = es.first.size @cs = es.map { |e| (ct = CoThread.new).fork do e.each do |x| ct.pass(x) end end } end def each @size.times do yield @cs.map{ |c| c.pass } end end end if $0 == __FILE__ foo = SyncEach.new(0..3, 10..13, 20..23) foo.each do |a| p a end end ---$ sync-each2.rb >行数を比較してみるとわかりますが、ほとんど同じです。 そうですね。まねして Thread による CoThread を作ってみました。 やはり、ほとんど同じですね。 ---^ co-thread-queue.rb require 'thread' class CoThread def queue Thread.current[:queue] ||= SizedQueue.new(1) end def initialize @queues = [] end def fork Thread.start do @queues.push(queue) x = queue.deq r = yield(x) @queues.shift.enq(r) end self end def pass(x = nil) @queues.push(queue) @queues.shift.enq(x) queue.deq end end if $0 == __FILE__ ct = CoThread.new ct.fork do |x| puts x puts 2 puts ct.pass(2.5) puts 5 5.5 end ct.fork do |x| puts x puts 3 puts ct.pass(3.5) puts 6 6.5 end puts 1 puts ct.pass(1.5) puts 4 puts ct.pass(4.5) puts 7 end ---$ co-thread-queue.rb これは、ほぼ co-thread.rb と互換で、YaProc, SyncEach, Generator, CoQueue すべて動作します。 、、、ということは Thread があれば、Proc はいらないのか、、、 >というわけで、 > >> それぞれ、Thread を使うとかなり気を使わなければならないところが、 >> ずいぶん素直に書けていると思います。 > >という主張は、やはり、単にロックを気にしなくていいというところに起因す >るのであろうという結論に至りました。 いえ、それはそうなんですが、そこが大事ではないでしょうか。「ずいぶん 素直に書けている」とは、例えば thread.rb などのライブラリのことを言っ たつもりでした。Mutex とか Queue とか SizedQueue とかの実装はかなり むずかしく、ほとんど「職人の技」です。それに比べれば callcc の扱いは、 順番にのみ注意すればよく、Thread があらゆるタイミングの組み合わせを 考えなれければならないのに比べ、(ライブラリの)プログラマにとっては 大分負担が軽いと思います。 >とくにライブラリは厄介で、こういうのを安全に使うには、全ての(あるいは >少なくとも大部分の)ライブラリが、常にクライアントのコードを実行したら >そこで継続を保存されて、何回も再入してくるという可能性を考慮して書かな >いといけません。これはライブラリの作者にとって負荷が高すぎ、しかも、そ >れに対して用途が少な過ぎる、というのが知合い(g新部さん)の callcc 有害 >論です。 私も、有害論者だけど面白がり、というところです。それでも限定した使 い方、例えば co-thread.rb による利用に限れば、そんなに問題ないので は。もちろん callcc がなくても書けるものはなしで書くべきで、そのた めのイテレータや Proc だったりするわけでから。 しかし、Thread と Continuation、どちらでも書けるなら前者でなければ ならない、という理由もない気もします。