Go の channel のようなものとして、Ruby には Queue クラスが用意されている。これを使えば、Rob Pike の説明していたサンプル (A multiplexed server) をほぼそのままの形で Ruby に直すことができる。対応するプログラミング要素はこんな感じ(↓):
Go | Ruby | |
---|---|---|
channel型 | → | Queue クラス |
func型 | → | ブロック |
goroutine | → | Thread クラス |
ちなみに、今回使った Ruby は Snow Leopard に標準のもの。バージョンはこれ(↓):
[macmini:~] mnbi% which ruby /usr/bin/ruby [macmini:~] mnbi% ruby -v ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]
コードはこうなる。コメントもオリジナルのものをそのまま相当する場所に記入しておいた。
(multi_server.rb)
1: require 'thread'
2:
3: class Request
4: def initialize(a, b, q)
5: @a = a
6: @b = b
7: @replyq = q # reply queue inside the Request
8: end
9: attr_reader :a, :b, :replyq
10: end
11:
12: def run(req, op)
13: req.replyq.enq(op.call(req.a, req.b))
14: end
15:
16: def server(service, op)
17: loop {
18: req = service.deq # requests arrive here
19: Thread.start(req) do |r|
20: run(r, op)
21: end
22: }
23: end
24:
25: def start_server(&op)
26: req_queue = Queue.new
27: Thread.start(req_queue, op) do |rq, o|
28: server(rq, o)
29: end
30: return req_queue
31: end
32:
33: # Start server; recieve a queue on which to send requests.
34: server = start_server {|a, b| (a + b)}
35:
36: # Create requests
37: req1 = Request.new(23, 45, Queue.new)
38: req2 = Request.new(-17, 1 << 4, Queue.new)
39:
40: # Send them in arbitrary order
41: server.enq(req1)
42: server.enq(req2)
43:
44: # Wait for the answers in arbitrary order
45: puts "Answer2: #{req2.replyq.deq}"
46: puts "Answer1: #{req1.replyq.deq}"
オリジナルの Go コードと並べてみれば、ほぼ一対一に対応していることがわかる。
Go のサンプルにあった、channel に対する select を使った server は、Ruby の Queue では簡単に実現できない。Ruby に用意されている select (Kernel.select または IO.select) には IO オブジェクトしか使えない。Queue ではダメなのだ。Queue に対する select に相当する仕組みを Queue や Thread のメソッドを使って作ることは可能だ(と思う)けど、ちょっと面倒なことになる。
ちなみに実行結果は以下のとおり。ちゃんと動いた。
[macmini:~] mnbi% ruby multi_server.rb Answer2: -1 Answer1: 68
関連リンク
関連記事
参考文献
まつもと ゆきひろ, David Flanagan
オライリージャパン ( 2009-01-26 )
ISBN: 9784873113944
おすすめ度:
オライリージャパン ( 2009-01-26 )
ISBN: 9784873113944
おすすめ度:
0 件のコメント:
コメントを投稿