- Ruby 4.0 の Ractor 使ってみた (1) 触ってみるまで
- Ruby 4.0 の Ractor 使ってみた (2) 題材
- Ruby 4.0 の Ractor 使ってみた (3) Ractor::Port に馴染む
- Ruby 4.0 の Ractor 使ってみた (4) Ractor に馴染む
- Ruby 4.0 の Ractor 使ってみた (5) 設計方針
- Ruby 4.0 の Ractor 使ってみた (6) 実装
- Ruby 4.0 の Ractor 使ってみた (7) ベンチマークテスト
どんな題材がよいか
並列処理の題材として取り組みやすいのは,「時間のかかる独立な処理が多数ある」タイプだろう。
処理が独立でない場合,一つの処理の結果を待って別の処理を,などというのは非常にややこしい。最初に取り組む題材として適していない。
また,個々の処理が軽すぎる場合,並列化にともなうオーバーヘッドが相対的に大きくなって,並列化のうまみが減るはずだ。
そこで,「文字列の配列を与え,各要素に何らかの処理を施した結果を取得する」ことにしたい。
「何らかの処理」としては「文字列に含まれる文字の出現頻度を頻度順に並べたハッシュを返す」としよう。
たとえば "Mississippi"(ミシシッピ)という文字列を与えたら
{"i" => 4, "s" => 4, "p" => 2, "M" => 1}
というハッシュを返す,と。
この処理の重さはどのくらいか?
手元の環境では,1 MiB 程度の英文テキストで数十 ms という感じだった。
よって,数十個か百個くらいのテキストについてやらせれば,並列化しない場合,全体の処理時間が秒の位になるので,実験するのにちょうどいいだろう。
各要素に対する処理
テキストデータに対する処理は以下のように書ける。
def char_histogram(text)
text.chars.tally.sort_by{ -_2 }.to_h
end
まず String#chars で文字の配列にしておき,Enumerable#tally で頻度表ハッシュを作る。
それを「頻度の符号を反転したもの」でソートすれば,多いもの順に並ぶ。ただ,それだと配列になってしまうので,Array#to_h でハッシュにする,というわけだ。
並列化しない場合の実装
並列化しない場合,さきほどの char_histogram メソッドを使えば以下のように,いとも簡単に書ける。
texts = [
"Mississippi",
"Colorado"
]
result = texts.map{ char_histogram(_1) }
# =>
# [
# {"i" => 4, "s" => 4, "p" => 2, "M" => 1},
# {"o" => 3, "C" => 1, "l" => 1, "r" => 1, "a" => 1, "d" => 1}
# ]
次回から,ひとまず Ractor とポートを触ってみよう。
これらがどういうものか分からないと方針の立てようもないから。