From: daniel@...42.com Date: 2020-11-13T19:53:41+00:00 Subject: [ruby-core:100842] [Ruby master Feature#17323] Ractor::LVar to provide ractor-local storage Issue #17323 has been updated by Dan0042 (Daniel DeLorme). Would it be possible to somehow have ractor-local variables that are automatically dereferenced instead of having to append `.value` everywhere? I'm thinking of cases like this where a class-level mutable constant (or classvar) makes it hard to make this code compatible with ractors. ```ruby class X # original, not compatible with Ractor, so how do we fix? CACHE = {} # like this, except now we need to append .value to every CACHE access CACHE = Ractor::LVar.new{ {} } def initialize(value) @value = value end def analyzed # here, lookup of CACHE constant could automatically return the # ractor-local Hash inside the LVar instead of the LVar itself CACHE[@value] ||= analyze(@value) end end ``` The problem with the example above is that it's too magical to have a variable or constant return an object different from what was assigned. So what I'm saying is that I'd like _something like_ this, that achieves the same effect. I have the feeling that a different syntax would be needed, to differentiate it from assignment. Maybe `CONST: expr` could be used to lazily evaluate `expr` once per ractor; then it would make sense for `CONST` to return this value rather than the LVar used behind the scenes. The example above would become `CACHE: {}`. But of course introducing new syntax is not something to be done lightly. ---------------------------------------- Feature #17323: Ractor::LVar to provide ractor-local storage https://bugs.ruby-lang.org/issues/17323#change-88484 * Author: ko1 (Koichi Sasada) * Status: Open * Priority: Normal ---------------------------------------- Ruby supports thread and fiber local storage: * `Thread#[sym]` provides *Fiber* local storage * `Thread#thread_variable_get(sym) These APIs can access other threads/fibers like that: ```ruby th = Thread.new{ Thread.current.thread_variable_set(:a, 10) } th.join # access from main thread to child thread p th.thread_variable_get(:a) ``` To make Ractor local storage, this kind of feature should not be allowed to protect isolation. This ticket propose alternative API `Ractor::LVar` that allows to provide Ractor local variable. ```ruby LV1 = Ractor::LVar.new p LV1.value #=> nil # default value LV1.value = 'hello' # can set unshareable objects because LVar is ractor local. Ractor.new do LV1.value = 'world' # set Ractor local variable end.take p LV1.value #=> 'hello' # Lvar.new can accept default_proc which should be isolated Proc. LV2 = Ractor::LVar.new{ "x" * 4 } p LV2.value #=> "xxxx" LV2.value = 'yyy' Ractor.new do p LV2.value #=> 'xxx' end p LV2.value #=> 'yyy' ``` This API doesn't support accessing from other ractors. `Ractor::LVar` is from `Ractor::TVar`, but I have no strong opinion about it. For example, `Ractor::LocalVariable` is longer and clearer. Implementation: https://github.com/ruby/ruby/pull/3762 -- https://bugs.ruby-lang.org/ Unsubscribe: