読者です 読者をやめる 読者になる 読者になる

ちなみに

火曜日の空は僕を押しつぶした。

Eldritch という非同期処理をDSLライクに書けるライブラリを試した

まえがき

今週の Ruby Weekly の Featured に上がっていたライブラリを試した。

https://github.com/beraboris/eldritch

これは何

非同期処理をDSLライクに書けるライブラリ。非同期処理といっても格好よくThreadを作っているだけ。

何がおもしろいのか

書き方がおもしろい。以下のように書ける。修飾子みたい。

async def task
   # ...
end

これは Ruby 2.1 から def がメソッド名をシンボルで返すようになったから出来る記法で、今後は Eldritch のように修飾子のような記法を使うライブラリが出てきそう。 private def securet; end で喜んでいる場合じゃなかった。

使ってみた

# 範囲を限定したい場合は `eldritch/safe` を使う
require "eldritch"

class Task
  def initialize(name)
    @name = name
  end

  def execute
    puts "execute: %s" % @name
  end
end

# 非同期メソッドの定義
# 実態は `__async_generate` というメソッドを定義して、
# 元のメソッドを `async` ブロックで囲って send している。
async def generate(name)
  loop do
    task = Task.new(name)
    $tasks << task
    sleep rand(0.5)
  end
end

$tasks = []

# together で囲むと Eldritch::Group が生成される
# グループに対して join や interrupt を呼ぶと
# 所属するすべての Thread に同時に送られる
together do |group|
  # 非同期メソッドの呼び出し
  generate("command 1")
  generate("command 2")
  generate("command 3")
  generate("command 4")
  generate("command 5")

  # ブロックでも非同期タスクを作ることができる
  # 実際には Thread を作って `call` しているだけ
  # 自動的に現在のグループに追加される
  async do
    10.times do
      sleep 0.1
      task = $tasks.pop
      next if task.nil?
      task.execute
    end

    # グループに対して `interrupt` を呼んでいるので、
    # この Thread *以外* の同じグループの Thread が止まる。
    group.interrupt
  end
end
$  ruby main.rb                                                                                                                                                                                                         
execute: command 5
execute: command 4
execute: command 4
execute: command 1
execute: command 3
execute: command 3
execute: command 3
execute: command 2
execute: command 1
execute: command 5

中学生的な感想

  • Thread を使っているのであまり実用的ではないが、記法がとてもおもしろかった。
  • コードがシンプルなので読みやすかった。
  • うしろを Celluloid にするとよさそう。