Class: Farce::Lazy
- Inherits:
-
Abstract::Lazy
- Object
- Abstract::Lazy
- Farce::Lazy
- Includes:
- Shareable::Tracked
- Defined in:
- lib/farce/lazy.rb
Overview
A ractor-shareable lazy value that is computed on demand.
The factory runs once. Its result is transferred according to #mode.
With the default :copy mode, each Ractor receives its own cached copy.
The factory and its bound receiver must remain Ractor-shareable.
Use Strict::Lazy for direct shareable results or Unshared::Lazy for local factories.
You can use it to make the following, common Ruby idiom ractor-safe:
class MyClass
def expensive_attribute = @expensive_attribute ||= compute_expensive_attribute
private
def compute_expensive_attribute
sleep 0.5 # pretend like we're working
42
end
end
# this will freeze the object without the expensive attribute being computed
object = Ractor.make_shareable(MyClass.new)
# this will fail
Ractor.new(object) { it.expensive_attribute }
object = MyClass.new
# this will work, but compute the expensive attribute five times, and also deep-copy any other
# unshareable data the object might hold
5.times { Ractor.new(object) { it.expensive_attribute } }
You can use Farce::Lazy to make expensive attributes ractor-safe:
class MyClass
include Farce::Shareable
def initialize
@expensive_attribute = Farce::Lazy.new do
sleep 0.5 # pretend like we're working
42
end
super
end
def expensive_attribute = @expensive_attribute.value
end
object = MyClass.new
# Will only compute the expensive attribute once, and return the same value to all Ractors.
5.times { Ractor.new(object) { it.expensive_attribute } }
Instance Method Summary collapse
-
#freeze ⇒ self
Resolve the slot before freezing it.
-
#initialize(factory = nil, mode: :copy) ⇒ Lazy
constructor
Valid modes are: *
:copy- The value will be copied between Ractors. -
#mode ⇒ Symbol
The transfer mode for the computed result.
-
#value ⇒ BasicObject
Compute once and return the result according to the configured transfer mode.
Methods included from Shareable
Methods included from Abstract::Value
Methods included from Internal::Copyable
Constructor Details
#initialize(factory, mode: :copy) ⇒ Lazy #initialize(mode: :copy, self: nil) { ... } ⇒ Lazy
Valid modes are:
:copy- The value will be copied between Ractors. This is the default mode.:make_shareable- The value will be made Ractor-shareable using Ractor.make_shareable.:move- The value will be moved between Ractors. This saves memory compared to copying, and supports values that can't be copied but moved (like IO objects). However, the value will no longer be accessible on the Ractor that pushed it.:mutable- A Mutable instance will be created for the value. This isn't done recursively and thus will fail for nested unshareable values.:local- The value will be kept local to the Ractor that pushed it. Another ractor trying to receive it will get an error. Useful for usage contained within a single Ractor.:proxy- The value will be wrapped in aFarce::Proxythat executes calls in the original Ractor.:raise- An error will be raised if the value is not Ractor-shareable. Useful for enforcing shareability.:dedup- The value will be deduplicated using Farce.dedup, then made Ractor-shareable. This may update and freeze the original. Already-shareable values pass through unchanged.:shareable_copy- The value will be copied and the copy will be made Ractor-shareable.
74 75 76 77 |
# File 'lib/farce/lazy.rb', line 74 def initialize(factory = nil, mode: :copy, **, &) @manager = marshal_mode_manager(mode) super(factory, **, &) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Farce::Abstract::Lazy
Instance Method Details
#freeze ⇒ self
Resolve the slot before freezing it. This does not freeze the result.
89 90 91 92 93 |
# File 'lib/farce/lazy.rb', line 89 def freeze value internal_atom.freeze super end |
#mode ⇒ Symbol
Returns the transfer mode for the computed result.
80 |
# File 'lib/farce/lazy.rb', line 80 def mode = @manager.mode |
#value ⇒ BasicObject
Compute once and return the result according to the configured transfer mode. Repeated reads return the same value within the current Ractor.
85 |
# File 'lib/farce/lazy.rb', line 85 def value = @manager.unwrap(super) |