Io languageでタイマー

Ioを使っていていつも思うのが、どうやってタイマーを実装するか。という問題

たとえば、3秒毎に特定の処理をしたくなった時、こんなコードを書いてしまいたくなる

1
2
3
4
5
6
7
loop (
  proc1
  proc2
  proc3
  :
  wait(3)
)

一見動いてしまうけど
でも、これは実はダメで loop でブロックされてしまうし、 wait 時にスレッドがブロックされてしまう

もうかれこれ3年くらい前に実装したものが↓
/lang/io/Timer – CodeRepos::Share – Trac

まぁ、なんとなく動くんだけど、System sleepwait は全体がブロックされてしまう問題があり 同時並行性に問題があった
(そもそも 0.01 sec で sleep してるあたりが問題すぎる)

ということで、これをどうにかして解決したいなぁ。と3年ぶりに思い至り Addon の Concurrency Thread でどうにか出来るんじゃないか。ということで、 non-blocking な実装を考えてみた

実装としては、親スレッドで 時間を受け取る Server を立ててしまって、子スレッドを生成して
その子スレッド内で sleep すれば親スレッドをブロックさせないという仕掛け

親スレッドはこんな感じに作っておいて

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Timer Interval Loop := Server clone do (
  setPort(11002)

  listener := Map clone

  addListener := method(id, callback,
    listener atPut(id, callback)
  )

  Handler := Object clone do (
    handle := method(socket, server,
      while(socket isOpen,
        if(socket read) then (
          data := socket readBuffer
          id := data beforeSeq(":")
          timestamp := data afterSeq(":")
          if(server listener hasKey(id)) then (
            callback := server listener at(id)
            callback @call(id, timestamp asNumber)
          )
        )
        socket readBuffer empty
      )
      socket close
    )
  )

  handleSocket := method(socket, Handler clone @handle(socket, self))
)

子スレッドはソケットで書き込んであげている

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
thread = Thread createThread("""
  id := "#{id}"
  host := "localhost"
  port := #{Timer Interval Loop port}
  interval := #{interval}

  socket := Socket clone
  socket setHost(host)
  socket setPort(port)
  socket connect

  if (socket isOpen) then (
    "client connected" println
  ) else (
    Exception raise("connection failed")
  )

  timestamp := Date now asNumberString
  msg := "\#\{id\}:\#\{timestamp\}"
  loop(
    timestamp := Date now asNumberString
    socket write(msg interpolate)
    wait(interval)
  )
""" interpolate)

まぁ、時間でブロックされずにコールバックをとれる javascript の setTimeoutsetInterval がすごいなぁ。ってのとそれをどうやって io で作ろうかなと思った奮闘記