(Tips) GPhysのお手軽な並列処理

作成者:樫村 博基

概要

Rubyのparallelライブラリを使って、GPhysの並列処理を行う。手軽にできることを重視する。

基本的にはGPhys.each_along_dimsメソッドと同じ発想で、ある軸に沿って分割して小分けに処理を行う。

2GB超のデータ処理にも有効。

なお、numru-narrayが使える場合は、narrayレベルでOpenMP&2GB超に対応しているので、このTipsは必要ない。

parallel のインストール

(sudo) gem install parallel

parallelの概要や詳しい使い方は https://github.com/grosser/parallel を参照のこと。

使用例

[x, y, z, t] = [480, 240, 120, 119] の次元を持つ大きめのGradsデータ(U.ctl)があるとする。

これの時間平均を計算する。

require "numru/gphys"
require "parallel"
include NumRu

gp = GPhys::IO::open("U.ctl","U")

np = 4 # 並列数
dd = "z" # 分割する軸(次元)
da = gp.coordinate(dd).val.to_a # 分割する軸をArray化したもの

gparray = Parallel.map(da, :in_processes=>np){|i| #このブロックが並列処理される
  gp_subset = gp.cut_rank_conserving(dd=>i)  # サブセットを取り出す
  gp_subset.mean("t") # 処理を記述
}
gp_result = GPhys.join(gparray) # 分割されたものを1つにまとめる

p gp_result

結果

2.8 GHz Intel Core i7(4コア)、メモリ16GB、Ruby 2.3.0の環境で実施して、実行時間をtimeコマンドで計測。

4並列
 22.15 real        36.35 user        24.77 sys
2並列
 29.28 real        32.02 user        19.76 sys
並列なし(np=0)
 47.85 real        29.68 user        18.07 sys

Parallel.mapのオーバーヘッドと GPhys.join の処理がそこそこ重いので、注意が必要。

注意点

データがNetCDFの場合、上記のようなコードだと

Error 22: Invalid argument 

というエラーがでる。(NetCDF側の制約?)

対策としては、Parallel.map のブロック内で、再度

gp = GPhys::IO::open("U.nc","U")

などと呼べば、回避できる。

おまけ

gem ruby-progressbar をインストールして、requireして、 Parallel.mapに :progress=>"progress" を追加すると、parallelブロック内の処理の進捗を示すプログレスバーが表示される。

progress | ETA: 00:00:06 | ================================                             | Time: 00:00:07
更新日時:2016/03/12 01:05:10
キーワード:[parallel]
参照: