💎
Ruby 3.2 - Fiber
Ruby 3.2 アドベントカレンダーの24日目の記事です。
Fiber
Fiber[], Fiber[]=, Fiber#storage 追加
Fiber ストレージというのが導入された。Fiber ローカルなストレージだけど、親 Fiber から継承される。子 Fiber で設定したものは親には反映されない。
Fiber[key]=value
で値を設定して Fiber[key]
で値を取り出せる。ストレージ全体は Fiber#storage
で参照できる。
Fiber[:hoge] = 123
p [:p1, Fiber[:hoge]] #=> 設定された 123
f = Fiber.new do
p [:c1, Fiber[:hoge]] #=> 親から継承された 123
Fiber[:hoge] = 456
p [:c2, Fiber[:hoge]] #=> 子で設定した 456
end
f.resume
p [:p2, Fiber[:hoge]] #=> 親は 123 のまま
p Fiber.current.storage #=> {:hoge=>123}
p f.storage #=> {:hoge=>456}
実行結果:
[:p1, 123]
[:c1, 123]
[:c2, 456]
[:p2, 123]
{:hoge=>123}
{:hoge=>456}
Fiber.new(storage: {...})
で Fiber 生成時に初期状態を設定できる。
Fiber.new(storage: {hoge: 123}) do
Fiber[:hoge] #=> 123
end
Fiber#storage=
で設定もできるが、これは experimental らしい。けど別に warning が出るわけではない。
f = Fiber.new(storage: {hoge: 123}) do
Fiber[:hoge] #=> 456
end
f.storage = {hoge: 456}
f.resume
Ruby は Thread#[]=
でスレッドローカルに値を保持できる…と思いきや実はこれはスレッドローカルではなくて Fiber ローカルだという罠があって、真にスレッドローカルに値を保持するには Thread#thread_variable_set
を使う必要があったりして、ややこしい。
3.2 からは Fiber ローカルなストレージは Fiber[]
を使えばいいということになって、すこしはマシになるのかもしれない。
将来的には Thread#[]
が真にスレッドローカルなストレージになったりするんだろうか。互換の問題があるからそれはないのかな…。
Discussion