@ledsun blog

無味の味は佳境に入らざればすなわち知れず

Ractorちゃん並列化してたー。

インスタンス生成コストが大きかった - @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したときは、上手くデータが取れませんでした。 とれていたら、もうちょっと早く気がつけていたのでしょうか?