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#[]
が真にスレッドローカルなストレージになったりするんだろうか。互換の問題があるからそれはないのかな…。