LoginSignup
1
0

More than 3 years have passed since last update.

socketry/asyncめも

Posted at

puppeteer-rubyっていうライブラリを作っているときに、WebSocketのコールバック順序がぐちゃぐちゃになる事象に嫌気がさして、WebSocketの代替実装を探していたところ、
(ぜんぜんWebSocketではないがw)asyncという面白そうなライブラリを見つけたのでメモ。

複数のタスクを待ち合わせる

require 'async'

def do_task(name)
  Async do |task|
    puts "start task - #{name}"
    task.sleep(name.to_i)
    puts "end task - #{name}"
    name
  end
end

def all_task(*args)
  Async do |task|
    puts "start tasks - #{args}"
    values = args.map do |arg|
      do_task(arg)
    end
    puts "wait for tasks....."
    result = values.map(&:wait)
    puts "end tasks - #{result}"
    result
  end
end

all_task(1,2,3,4,5) を実行すると

start tasks - [1, 2, 3, 4, 5]
start task - 1
start task - 2
start task - 3
start task - 4
start task - 5
wait for tasks.....     # ここまで一瞬
end task - 1
end task - 2
end task - 3
end task - 4
end task - 5            # ここまで、1秒毎に
end tasks - [1, 2, 3, 4, 5] # ↑と同時

JSでいうところの Promise.all (せんぶまつ)はできるが、
Promise.race (どれか1つが終わるまで待つ)ができるかはまだ確かめていない。

あと、トップレベルでの実行(Async do ... endをしない状態)では、並列実行にならずタスクは直列実行された。
Async do ... end 内に限り並列実行されるようだ。

Async::Queue

Promiseのように、誰かがresolveしてくれるまで待ち受けるようにしたいときは、Queueを使うとよさそう?

require 'async'
require 'async/queue'

def resolvable
  Async do |task|
    q = Async::LimitedQueue.new
    Async do
      puts "q start"
      result = q.dequeue
      puts "q end - #{result}"
    end
    task.sleep 3
    q << 3
  end
end

これも、外側の Async ... end を忘れると、内側の Async...do を待ち受けようとするため、このブロックが抜けられず、task.sleepまでたどり着かない。

 

ドキュメンテーションが若干弱いいけど、重厚なconcurrent-rubyに比べると単機能で手軽に使えて良さそう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0