Project

General

Profile

Actions

Feature #21953

open

Allow accessing unshareable objects within a Ractor-local Ruby Box

Feature #21953: Allow accessing unshareable objects within a Ractor-local Ruby Box

Added by tikkss (Tsutomu Katsube) about 24 hours ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:125003]

Description

Status

Currently, non-main ractors prohibit access to the following objects to prevent data races:

  • Global variables
  • Class variables
  • Unshareable class instance variables
  • Unshareable constants

Proposal

I would like to propose that allow reading/writing unshareable objects inside a Ruby Box created in a non-main ractor:

# lib/x.rb
class X
  # can write unshareable objects
  XXX = "1"
  @@cvar = "1"
  @ivar = "1"

  class << self
    def cvar; @@cvar; end
    def ivar; @ivar; end
  end
end

# can read unshareable objects
$LOAD_PATH # => returns $LOAD_PATH includes lib directory
X.cvar # => "1"
X.ivar # => "1"
X::XXX # => "1"

# main.rb
Ractor.new do
  local_box = Ruby::Box.new
  local_box.eval <<~RUBY
    base_dir = File.expand_path(File.dirname(__FILE__))
    lib_dir = File.join(base_dir, "lib")
    # can write unshareable objects
    $LOAD_PATH.unshift(lib_dir)
  RUBY
  local_box.require("x")
  x = local_box::X.new
end.join

Ruby Box can isolate global/class variables, class/module definitions from other boxes.

A Ruby Box created inside a non-main ractor cannot be accessed from other ractor.

If that is the case, wouldn’t it be fine to access unshareable objects inside that box?

So I would like to propose that allow reading/writing unshareable objects inside a Ruby Box created in a non-main ractor.

Background

We are working on implementing a Ractor based parallel test runner for the test-unit gem.

Ractor is a great for parallel processing. However, many existing libraries still rely on class variables or class instance variables for configuration.

Ideally, we should reduce the use of class variables or class instance variables.
Currently, we tried fixing several non-shareable objects, but we could not resolve all of them yet.

We will continue working on this issue, but we are also exploring other approaches. This is the idea begind this proposal.

I think the work needed to make objects shareable when running exisiting libraries with Ractor can be reduced.

FAQ

Q: Can we create a Ruby Box inside a non-main ractor?
A: Yes:

Ractor.new {Ruby::Box.new}.join

Q: Is a Ruby Box created in a non-main ractor truly inaccessible from other ractor?
A: No. I'm not sure if it's intentional, but a Ruby Box is a shareable object. Also, it can be accessed from the main Ractor by using Ractor#value:

Ractor.shareable?(Ruby::Box.new) # => true
Ractor.new {Ruby::Box.new}.value # => #<Ruby::Box:3,user,optional>

To implement this proposal, Ruby Box may need to be an unshareable object, and passing it with Ractor#value may need to be disallowed.

No data to display

Actions

Also available in: PDF Atom