Feature #20627
closed`require` on Ractor should run on the main Ractor
Description
Now require
on main Ractor is not allowed (raising error) but it is hard, especially for autoload
.
So let's allow require
by running it on the main Ractor.
Background¶
On many libraries it is needed to run loading on the main Ractors because:
- Setup constants with unshareable objects (such as
C = []
) are not allowed on non main Ractors. - Setup global variables and class variables are not allowed.
$LOADED_FEATURES
is also untouchable. - (maybe more reasons)
So the require
on non main Ractors is not allowed.
However it is hard to program especially on autoload
.
Also dynamic require
(require
in methods) are not allowed too (pp
method, for example).
Proposal¶
Allow require
on non main Ractors by running require
process on the main Ractor.
(quoted on my talk at RubyKaigi 2024)
rb_ractor_interrupt_exec(target_ractor, func)
C-API
Make a thread on target_ractor
and run func
(C function) on it.
I think it is safe to expose on Ruby API because running func
on a newly created thread (do not disturb running target threads). But now it is proposed as only (hidden) C-API.
New Ractor methods¶
-
Ractor.main?
returns Ractors -
Ractor.require(feature)
dorequire
on the main Ractor
These new methods are useful for users who override require
method like RubyGems.
alias orig_require require
def require feature
return Rator.require(feature) if defined?(Ractor.main?) && !Ractor.main?
# overriding require code
end
Or we can prepend a module like:
Module.new do
def require(feature)
return Rator.require(feature) if defined?(Ractor.main?) && !Ractor.main?
super(feature)
end
Kernel.prepend self
end
will support ractors for all overgrinding methods. But not sure it is acceptable to add additional one modules in ancestors by prepend
.
Also this technique doesn't support require overriding by prepending.
Implementation¶
https://github.com/ruby/ruby/pull/11142 (not matured yet)
Files
Updated by luke-gru (Luke Gruber) 6 months ago
Now require on main Ractor is not allowed (raising error)
I think you mean non-main Ractor. I like this change, I think it's necessary to get wider adoption for Ractors due to the autoload issue you mentioned. The change should be documented well in the require
docs and the Ractor
docs once the implementation is mature since it's a fairly major change imo.
Updated by jeremyevans0 (Jeremy Evans) 5 months ago
- Tracker changed from Bug to Feature
- Backport deleted (
3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN)
Updated by ko1 (Koichi Sasada) 4 months ago
I want to add new features:
-
Ractor._activated
which is called when the firstRactor.new
is called -
Ractor._require(feature)
described in this issue -
_activated
method usesprepend
with new anonymous module to callRactor._require
when therequire
is called on non-main Ractors.
class Ractor
class << self
private
# internal method
def _require feature
if main?
super feature
else
Primitive.ractor_require feature
end
end
# internal method that is called when the first "Ractor.new" is called
def _activated
Kernel.prepend Module.new{|m|
m.set_temporary_name '<RactorRequire>'
def require feature
if Ractor.main?
super
else
Ractor.__send__ :_require, feature
end
end
}
end
end
I think most of require
can be ractor supported.
If a library uses same technique (prepend to override require), the library should call Ractor._require
by itself.
Updated by hsbt (Hiroshi SHIBATA) 3 months ago
- Status changed from Open to Assigned
Updated by ko1 (Koichi Sasada) about 2 months ago
- Status changed from Assigned to Closed
Applied in changeset git|aa63699d10e489bc6d9c13406fc47f581001568b.
support require
in non-main Ractors
Many libraries should be loaded on the main ractor because of
setting constants with unshareable objects and so on.
This patch allows to call requore
on non-main Ractors by
asking the main ractor to call require
on it. The calling ractor
waits for the result of require
from the main ractor.
If the require
call failed with some reasons, an exception
objects will be deliverred from the main ractor to the calling ractor
if it is copy-able.
Same on require_relative
and require
by autoload
.
Now Ractor.new{pp obj}
works well (the first call of pp
requires
pp
library implicitly).
[Feature #20627]