インスタンス生成コストが大きかった - @ledsun blog までやった結果、Ractor間で受け渡しているデータ構造が大分はっきりしました。
ここまできたら、送信データを保存しておけば、Ractor化している処理だけで実行出来るはずです。 次のような感じで、Ractorに送信するデータをシリアライズしてファイルに保存しておきます。
File.open("#{path}/#{doc.sourcedb}_#{doc.sourceid}", "wb", 0755) do |f| send_data = Marshal.dump({ index: index, ref_text: ref_text, options: options, data:data }) f.write(send_data) end
このデータファイルを読み込んでワーカーRactorに送り込めば、より厳密に並列化の効果が測定できます。 テキストアライメント処理のまえのデータ読み込みの部分をスキップできます。
次のスクリプトをつくって動かしてみます。
require 'text_alignment' require 'active_support' require_relative 'config/initializers/ractor.rb' pipe = Ractor.new do loop do Ractor.yield Ractor.receive end end workers = (1..4).map do Ractor.new pipe do |pipe| while msg = pipe.take aligner = TextAlignment::TextAlignment.new(msg[:ref_text], msg[:options]) results = msg[:data].map do |datum| begin aligner.align(datum[:text], datum[:denotations] + datum[:blocks]) { denotations: aligner.transform_hdenotations(datum[:denotations]), blocks: aligner.transform_hdenotations(datum[:blocks]), lost_annotations: aligner.lost_annotations, block_alignment: aligner.lost_annotations.present? ? aligner.block_alignment : nil } rescue => e break { error: e.message } end end Ractor.yield(Ractor.make_shareable({ index: msg[:index], results: results }), move: true) end end end Dir["./tmp/send_data20221122-2664*/*"].each.with_index do |file| send_data = Marshal.load(File.binread(file)) pipe.send(send_data) end.each do _r, results = Ractor.select(*workers) end
ワーカー数を1~4まで変えて処理時間をグラフ化します。
でました放物線ぽいグラフです! 4コアのローカルPCで試しました。 これ以上の並列数はAWS EC2環境で計測する必要があります。 とはいえ、ここまで典型的なグラフがでたなら、割と良い感じに並列化できてそうです。
Ruby並行・並列くらべ - @ledsun blog の頃から、ずっとRactorで並列化できているっぽいけど、おもったより性能伸びないなあ・・・と悩んでいました。 2ヶ月前です。 気がつけば当たり前の話です。 並列化したところは高速化できていました。 高速化したぶんボトルネックが、並列化してない処理に移動していただけでした。
Stackprofで時間の掛かる処理を探そうとして上手く行かなかった話 - @ledsun blog でStackprofしたときは、上手くデータが取れませんでした。 とれていたら、もうちょっと早く気がつけていたのでしょうか?