しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

【Ruby】Parallelで並列処理

ParallelというGemで並列処理を試してみました。

github.com

インストール

インストールはBundlerを使いました。

source "https://rubygems.org"

gem "parallel"

使い方

使い方は下の通りです。
1,2,3を引数にしたブロックを並列に実行してくれます。

require 'parallel'

puts 'Start'
Parallel.each([1, 2, 3]) do |i|
  puts i
end
puts 'End'

結果は下の通りです。

f:id:llcc:20180107122058p:plain

並列なことを確かめるために、下のようにiが2の時に1秒待つようにしてみました。

require 'parallel'

puts 'Start'
Parallel.each([1, 2, 3]) do |i|
  sleep 1 if i == 2
  puts i
end
puts 'End'

結果は下の通りです。
1,3,2の順番に出力されました。

f:id:llcc:20180107122037p:plain

下のようにスレッド数を指定する事もできます。

require 'parallel'

Parallel.each([1, 2, 3], in_threads: 2) do |i|
  puts i
end

スレッド数を1にすると、並列ではなくなるので全てが順番に実行されます。

require 'parallel'

Parallel.each([1, 2, 3], in_threads: 1) do |i|
  sleep 1 if i == 2
  puts i
end

f:id:llcc:20180107122530p:plain

スレッドではなくプロセスを使う事もできます。

require 'parallel'

Parallel.each([1, 2, 3], in_processes: 2) do |i|
  puts i
end

プロセスはブロック内での変数の変更が共有されません。

require 'parallel'

array = []
Parallel.each([1, 2, 3], in_processes: 2) do |i|
  array.push(i)
end
p array # → []

array = []
Parallel.each([1, 2, 3], in_thread: 2) do |i|
  array.push(i)
end
p array # → []

変数の共有をしたい場合は下のようにmapを使います。

require 'parallel'

array = Parallel.map([1, 2, 3]) do |i|
  i
end
p array # → [1, 2, 3]

mapの返り値は引数の順番を保持してくれます。
下のようにi==2の時だけsleepしても結果は1, 2, 3になりました。

require 'parallel'

array = Parallel.map([1, 2, 3], in_thread: 2) do |i|
  sleep 1 if i == 2
  i
end
p array # → [1, 2, 3]

もし別々の処理を実施したい場合は下のような書き方もできます。

require 'parallel'

Parallel.each([
  -> { p 1 },
  -> { p 2 },
  -> { p 3 },
  ]) do |l|
  l.call
end