I tried to make the following code work with Ractor.
r = Ractor.new do
v1, v2 = Ractor.recv
puts v1
puts v2
puts v1.class
puts v2.class
end
r.send(1, 2)
r.take
# => 1
# => 2
# => Integer
# => Integer
It is a mechanism to provide parallel / parallel functions introduced in Ruby3. Originally named Guild, it has been discussed for several years.
For more details, please refer to the video below.
[JA] Ractor report / Koichi Sasada @ko1
You can pass an object to Ractor using the send
method.
r = Ractor.new do
v = Ractor.recv
puts v
puts v.class
end
r.send(1)
r.take
# => 1
# => Integer
However, you cannot pass multiple objects as shown below.
r = Ractor.new do
v1, v2 = Ractor.recv
puts v1
puts v2
puts v1.class
puts v2.class
end
r.send(1, 2)
r.take
# =>wrong number of arguments (given 2, expected 1) (ArgumentError)
However, it seems OK to pass it as an array.
r = Ractor.new do
v1, v2 = Ractor.recv
puts v1
puts v2
puts v1.class
puts v2.class
end
r.send([1, 2])
r.take
# => 1
# => 2
# => Integer
# => Integer
Looking at the implementation, it looks like this (in ractor.rb
in the CRuby source code)
The current send
method takes only one object as an argument. You can also specify whether or not to move with the keyword argument move
.
def send obj, move: false
__builtin_cexpr! %q{
ractor_send(ec, RACTOR_PTR(self), obj, move)
}
end
The C function is called with __builtin_cexpr!
, and the argument received by the method is passed to the C function as it is. As an aside, recent CRuby allows you to write code that passes Ruby variables to C functions as an internal implementation.
I rewrote Ractor's send
method as follows.
def send obj, *arg, move: false
obj = arg.unshift obj unless arg.empty?
__builtin_cexpr! %q{
ractor_send(ec, RACTOR_PTR(self), obj, move)
}
end
First, the send
method always takes one object as an argument. The arguments are rewritten like ʻobj, * arg, move: falseto maintain that behavior. Also, if multiple objects are passed, such as
send (1, 2), the arguments are passed as an array to
* arg`.
If ʻarg is not an empty array, then multiple objects are being passed, and the ʻobj
that is finally passed to the C function is converted to a merge of the first argument and the variadic argument. I will.
All you have to do is build the modified CRuby source code.
You can now pass multiple objects to Ractor as follows:
r = Ractor.new do
v1, v2 = Ractor.recv
puts v1
puts v2
puts v1.class
puts v2.class
end
r.send(1, 2)
r.take
# => 1
# => 2
# => Integer
# => Integer
ref: Guild → Ractor ref: https://github.com/ko1/ruby/blob/ractor/ractor.ja.md ref: [[JA Ractor report / Koichi Sasada @ko1
By the way, if you want a monkey patch, you can create a method wrapped as follows.
class Ractor
def multi_send(obj, *args, move: true)
obj = args.unshift obj unless args.empty?
send(obj, move: move)
end
end
r = Ractor.new do
v1, v2 = Ractor.recv
puts v1
puts v2
puts v1.class
puts v2.class
end
r.multi_send(1, 2)
r.take
The range of monkey patches is wide, so if you use them in practice, it may be better to use refinements
because it has less effect.
module RefineRactor
refine Ractor do
def multi_send(obj, *args, move: true)
obj = args.unshift obj unless args.empty?
send(obj, move: move)
end
end
end
using RefineRactor
r = Ractor.new do
v1, v2 = Ractor.recv
puts v1
puts v2
puts v1.class
puts v2.class
end
r.multi_send(1, 2)
r.take
Recommended Posts