平たく言うとコルーチン対決。ついでに Squeak Smalltalk もスレッドで参戦。環境は 1GHz PowerPC, OS X 。
まず、一個あたりの生成にかかる時間を計測。
Ruby
(1..10).each do |n| GC.start num_fs = (n * 1e3).to_i t0 = Time.new root = Fiber.current fs = (1..num_fs).collect do | i | Fiber.new{ loop{ root pass } } end time = (Time.now - t0) * 1e3 fs = nil print "N = #{num_fs}, #{(time * 1.0e3 / num_fs).to_i} microseconds per fiber\n" end
結果。
N = 1000, 173 microseconds per fiber N = 2000, 251 microseconds per fiber N = 3000, 361 microseconds per fiber N = 4000, 426 microseconds per fiber N = 5000, 609 microseconds per fiber N = 6000, 677 microseconds per fiber N = 7000, 785 microseconds per fiber N = 8000, 839 microseconds per fiber N = 9000, 905 microseconds per fiber N = 10000, 1009 microseconds per fiber
Io はオブジェクトがアクターなので、オブジェクトの生成速度を計るかんじ。
Io
for(n, 1, 10, Collector collect numActors := n * 1e3 root := Coroutine currentCoroutine Actor := Object clone do( pass := method( loop( yield ) ) ) actors := List clone time := Date secondsToRun( numActors repeat( actors push(Actor clone) ) ) * 1e3 actors = nil writeln("N = ", numActors, ", ", (time * 1e3 / numActors) round, " microseconds per actor") )
N = 1000, 39 microseconds per actor N = 2000, 33 microseconds per actor N = 3000, 26 microseconds per actor N = 4000, 23 microseconds per actor N = 5000, 22 microseconds per actor N = 6000, 20 microseconds per actor N = 7000, 22 microseconds per actor N = 8000, 19 microseconds per actor N = 9000, 23 microseconds per actor N = 10000, 23 microseconds per actor
これは Io の圧勝。
続いて、リングノードベンチ。
Ruby
class Node attr_accessor :neighbor def initialize(m) @num_msgs = m @fiber = Fiber.new{ @num_msgs.times{ @neighbor.ping } } end def ping @fiber.pass end end m = 100 [10, 100, 1000].each do |n| first = prev = Node.new(m) (2..n).each do prev.neighbor = (prev = Node.new(m)) end prev.neighbor = first t0 = Time.now first.ping time = Time.now - t0 print "N = #{n}, M = #{m}, #{(time * 1e3).to_i} milliseconds\n" end
N = 10, M = 100, 6 milliseconds N = 100, M = 100, 269 milliseconds N = 1000, M = 100, 3711 milliseconds
Io
m := 100 Node := Object clone do( newSlot("neighbor", nil) numMsgs := m ping := method( // writeln(numMsgs) if(numMsgs > 0, numMsgs = numMsgs - 1; neighbor @@ping) ) ) list(10, 100, 500) foreach(n, first := prev := Node clone for(i, 2, n, prev setNeighbor(prev = Node clone)) prev setNeighbor(first) Collector collect time := Date secondsToRun(first @@ping; yield) * 1e3 writeln("N = ", n, ", M = ", m, ", ", time round, " milliseconds") )
N = 10, M = 100, 1891 milliseconds N = 100, M = 100, 16362 milliseconds N = 500, M = 100, 93091 milliseconds
こちらは Ruby の圧勝。Ioぉ〜。がっかりだよっ!w
生成
| numProcess processes time | (1 to: 10) do: [:nn | Smalltalk garbageCollect. numProcess := nn * 1e3. time := [processes := (1 to: numProcess) collect: [:idx | [[Processor yield] repeat] newProcess]] timeToRun. processes do: [:proc | proc terminate]. World findATranscript: nil. Transcript cr; show: ('N = {1}, {2} microseconds per process' format: {numProcess. time * 1.0e3 / numProcess roundTo: 0.1})]
N = 1000, 10.0 microseconds per process N = 2000, 8.0 microseconds per process N = 3000, 7.3 microseconds per process N = 4000, 8.0 microseconds per process N = 5000, 8.0 microseconds per process N = 6000, 9.0 microseconds per process N = 7000, 7.9 microseconds per process N = 8000, 8.0 microseconds per process N = 9000, 8.1 microseconds per process N = 10000, 8.1 microseconds per process
リングノード
| m | m := 100. World findATranscript: nil. #(10 100 1000) do: [:n | | sema firstMailbox myMailbox time | sema := Semaphore new. firstMailbox := myMailbox := SharedQueue new. 1 to: n do: [:idx | | neighbor | neighbor := idx < n ifTrue: [SharedQueue new] ifFalse: [firstMailbox]. [ | numMsgs | numMsgs := m. [numMsgs > 0] whileTrue: [ "Transcript cr; show: numMsgs." numMsgs := numMsgs - 1. myMailbox next. neighbor nextPut: #ping]. idx = n ifTrue: [sema signal]] fixTemps fork. myMailbox := neighbor]. time := [firstMailbox nextPut: #ping. sema wait] timeToRun. Transcript cr; show: ('N = {1}, M = {2}, {3} milliseconds' format: {n. m. time})]
N = 10, M = 100, 27 milliseconds N = 100, M = 100, 239 milliseconds N = 1000, M = 100, 3704 milliseconds