🙌
[Feature #21028] Ractor の共有可能でないオブジェクトを見つける方法がほしいというチケット
[Feature #21028] Method for finding why an object isn't Ractor shareable
-
Ractorの共有可能でないオブジェクトを見つける方法がほしいというチケット - 任意のオブジェクトが共有可能オブジェクトかどうかは
Ractor.shareable?で判定できる
# 通常のオブジェクトは共有可能オブジェクトではない
obj = [1, 2, 3]
pp Ractor.shareable? obj # => false
# frozen の場合は共有可能オブジェクトとして扱われる
obj = [1, 2, 3].freeze
pp Ractor.shareable? obj # => true
- これはオブジェクトがネストしている場合にも判定できる
# すべてが frozen の場合は共有可能オブジェクトとして扱われる
obj = [
"homu".freeze,
"mami".freeze,
"mado".freeze,
].freeze
pp Ractor.shareable? obj
# => true
- こういう複雑な構造のオブジェクトの場合に『どのオブジェクトが共有可能オブジェクトでないのか』を見つける方法がほしいという意図になる
# 一部の要素が共有可能オブジェクトでなければ共有可能オブジェクトとして扱えない
obj = [
"homu".freeze,
"mami",
"mado".freeze,
].freeze
# これだけ見たときに『どれが共有可能オブジェクトでないのか』がわからない
pp Ractor.shareable? obj
# => false
- 具体的な案としては
Ractor.unshareable_references?やRactor.shareable?(obj) { |not_shareable_obj| }みたいなコードが提示されていますね - これなんですがコメントでは
ObjectSpace.reachable_objects_fromを利用した実装が提示されていますね-
ObjectSpace.reachable_objects_fromは『obj から到達可能なすべてのオブジェクトを返す』メソッド - ObjectSpace.#reachable_objects_from (Ruby 3.4 リファレンスマニュアル)
- これは知らなかった
- 要は
objに対してObjectSpace.reachable_objects_fromを利用してネストした走査を行いshareable?でないオブジェクトを探す、みたいな感じですかね
-
require "objspace"
def find_path_to_unshareable_object(obj, path = [], visited = {})
path += [obj]
return if visited[obj]
visited[obj] = true
return if Ractor.shareable?(obj)
objs = ObjectSpace.reachable_objects_from(obj)
return path if objs.all? { Ractor.shareable?(it) }
objs.each do |obj2|
res = find_path_to_unshareable_object(obj2, path, visited)
return res if res
end
return nil
end
pp *find_path_to_unshareable_object([1, 2, 3, "str".freeze, { :key => -> {} }])
#=> [1, 2, 3, "str", {key: #<Proc:0x00007f0a38e0ff30 t.rb:20 (lambda)>}]
#=> {key: #<Proc:0x00007f0a38e0ff30 t.rb:20 (lambda)>}
#=> #<Proc:0x00007f0a38e0ff30 t.rb:20 (lambda)>
#=> main
- 現在はこのコードをもとにした
ObjectSpace.find_paths_to_unshareable_objectsを追加する PR が出ているみたいですね
Discussion