詰まっているのはワーカーでなくパイプ? - @ledsun blog で、「Ractor間のデータ受け渡し時のコピーがボトルネックになっている」という仮説を立てました。
これを確認するために、Ractor間のデータの受け渡しをmoveにしてみます。
次のようにRactor#sendとRactor.yieldを使っている場所に move: true オプションをつけていきます。
pipe = Ractor.new do
loop do
msg = Ractor.receive
Ractor.yield(msg, move: true)
end
end
workers = (1..4).map do
Ractor.new pipe do |pipe|
while msg = pipe.take
a, ref_text, o = msg
aligner = TextAlignment::TextAlignment.new(ref_text, o)
m = a.map do |annotation|
Annotation.align_annotations!(annotation, ref_text, aligner)
end.flatten
Ractor.yield([m, a], move: true)
end
end
end
Ractor.make_shareable(options)
annotations_collection_with_doc = annotations_collection_with_doc.collect do |annotations, doc|
ref_text = doc.original_body.nil? ? doc.body : doc.original_body
ref_text.freeze
pipe.send([annotations, ref_text, options], move: true)
doc
end
これを実行すると次の3つのエラーが起きるようになりました。
実行するといずれかのエラーがおきて止まります。
安易にmoveオプションをつければいいわけではなさそうです。
パターン1 no implicit conversion of Symbol into Integer (TypeError)
14:07:32 workor.1 | #<Thread:0x00007fda6a006788 run> terminated with exception (report_on_exception is true):
14:07:32 workor.1 | /home/ledsun/pubannotation/app/models/annotation.rb:466:in `[]': no implicit conversion of Symbol into Integer (TypeError)
14:07:32 workor.1 | from /home/ledsun/pubannotation/app/models/annotation.rb:466:in `align_annotations!'
14:07:32 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:767:in `block (3 levels) in store_annotations_collection'
14:07:32 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:766:in `map'
14:07:32 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:766:in `block (2 levels) in store_annotations_collection'
Rubyで一番苦手なエラーです。
ハッシュの代わりに配列が渡されているのでしょうか?
エラーが起きている箇所は次のようなソースコードです。
def self.align_annotations!(annotations, ref_text, aligner)
return [] unless annotations[:denotations].present? || annotations[:blocks].present?
この呼び出し元は最初のソースコードのAnnotation.align_annotations!(annotation, ref_text, aligner)
です。
いままでハッシュで呼び出していたはずが、配列に変わることがあるみたいです。
同じ変数に格納されている値が変わっているのでしょうか?
何が起きているのか、いまいち想像できません。
パターン2 wrong argument type false (expected Class) (TypeError)
14:21:16 workor.1 | #<Thread:0x00007fda69e0cf18 run> terminated with exception (report_on_exception is true):
14:21:16 workor.1 | <internal:ractor>:627:in `yield': wrong argument type false (expected Class) (TypeError)
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:757:in `block (2 levels) in store_annotations_collection'
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:755:in `loop'
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:755:in `block in store_annotations_collection'
14:21:16 workor.1 | #<Thread:0x00007fda69e0ca90 run> terminated with exception (report_on_exception is true):
14:21:16 workor.1 | <internal:ractor>:694:in `take': thrown by remote Ractor. (Ractor::RemoteError)
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:763:in `block (2 levels) in store_annotations_collection'
14:21:16 workor.1 | <internal:ractor>:627:in `yield': wrong argument type false (expected Class) (TypeError)
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:757:in `block (2 levels) in store_annotations_collection'
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:755:in `loop'
14:21:16 workor.1 | from /home/ledsun/pubannotation/app/models/project.rb:755:in `block in store_annotations_collection'
見慣れないエラーです。
起きている箇所は最初のソースコードのRactor.yield(msg, move: true)
です。
pipe役のRactorがデータを送ろうとしたところで、エラーが起きているようです。
https://github.com/ruby/ruby/blob/v3_1_2/ractor.c を見てみます。
ractor_yield(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
{
VALUE ret_r;
ractor_select(ec, NULL, 0, obj, RTEST(move) ? true : false, &ret_r);
return Qnil;
}
Racter.yieldの引数はobjで、型エラーに引っかかりそうもありません。
どこかでそれらしい引数で rb_raise(rb_eArgError
しているのかというと、こっちもみつかりません。
このエラーはどこで何がおかしいのか、想像できません。
パターン 3 <OBJ_INFO:gc_mark_ptr@gc.c:6713> 0x00007fda6b47ec10 [2 M ] T_NONE
ながいのでgistにしました。
PubAnnotationでRactor#send move:true したときに起きたエラー · GitHub
このエラーが起きたときは最終的にSIGIOTでSidekiqプロセスが終了します。
僕は、C言語レイヤーのエラーを上手く読み解けません。
gc_mark_ptr とあるので、GCの途中でエラーが起きているのでしょうか?