(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
キーワード:[parallel]
参照: