Help us understand the problem. What is going on with this article?

Rubyの並列処理

はじめに

最近、複数メソッドを並列で処理するコーティングが行い、concurrent-rubyについて学んだので簡単にまとめました。

concurrent-rubyとは

concurrent-rubyは、並行処理のデザインパターン
を元に作られたGem。簡単に言えば、Rubyで並行処理が実行出来てしまうGemです。

サンプル

concurrent-rubyは、様々な作法が存在しますが、ネットで検索すると、単数形のPromiseやFutureなどと色々な書き方が出てきます。最近、Promisesで統一されつつあるらしいので、Concurrent::Promisesのサンプルを紹介します。

まずは、並列に実行したいProcオブジェクトを作成するメソッド(p1、p2、p3)を準備。今回は、それぞれのメソッドの中に、1secずつずらしたsleepを設けます。

def p1
  lambda {
    start_time = Time.now
    sleep 1
    return "p1 => start time: #{start_time}, finish_time: #{Time.now}s"
  }
end

def p2
  lambda {
    start_time = Time.now
    sleep 2
    return "p2 => start time: #{start_time}, finish_time: #{Time.now}s"
  }
end

def p3
  lambda {
    start_time = Time.now
    sleep 3
    return "p3 => start time: #{start_time}, finish_time: #{Time.now}s"
  }
end

pry(main)> p1
=> #<Proc:0x000055bb4bf3ad48@(pry):68 (lambda)>
pry(main)> p2
=> #<Proc:0x000055bb4bf16df8@(pry):75 (lambda)>
pry(main)> p3
=> #<Proc:0x000055bb4bef7660@(pry):91 (lambda)>

それぞれの処理を実行するスレッドを作成します。以下の状態では、pendingとなっており、まだ処理は実行されていません。

tasks = [p1, p2, p3].map { |p| Concurrent::Promises.future { p.call } }

=> [#<Concurrent::Promises::Future:0x000055bb4be2aac0 pending>,
 #<Concurrent::Promises::Future:0x000055bb4be29b20 pending>,
 #<Concurrent::Promises::Future:0x000055bb4be289f0 pending>]

zipとういうメソッドが用意されているのでそれを使用すると、同時にスレッドが実行され、それらの返り値が配列にまとめられます。

pry(main)> Concurrent::Promises.zip(*tasks).value! 
=> ["p1 => start time: 2019-06-12 18:23:01 +0900, finish_time: 2019-06-12 18:23:02 +0900s",
 "p2 => start time: 2019-06-12 18:23:01 +0900, finish_time: 2019-06-12 18:23:03 +0900s",
 "p3 => start time: 2019-06-12 18:23:01 +0900, finish_time: 2019-06-12 18:23:04 +0900s"]

start timeは実行時刻。同じ時刻(2019-06-12 18:23:01 +0900)から同時に実行されたことがわかります。また、finish_timeは1秒ずつずれています。逐次処理の場合は、sleepタイム毎に時刻がずれるため、これが並列処理で実行されていることがわかります。

まとめ

簡単にですが、Rubyの並列処理についてまとめました。今回は、非常に簡単な例ですが、まともに使おうとするとかなり手こずると思います。Railsアプリケーションに組み込もうとして実装を試みましたが、実装が複雑化してデバックがしにくくなるため、導入を断念しました。正直、Ruby自体が並列処理に向いてなさそうです。Railsアプリケーションならば、Sidekiqなどを使用して無理せず実装した方が良さそうですね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away