Preview Ruby 4.1 is a preview. It can change before the final release. Switch to Ruby 4.0 →
Ractor.select
# File tmp/rubies/ruby-4.1.0-preview1/ractor.rb, line 314
def self.select(*ports, timeout: nil)
raise ArgumentError, 'specify at least one Ractor::Port or Ractor' if ports.empty?
monitored = []
others = []
mp = nil
begin
ports.each do |arg|
case arg
when Ractor
monitored << arg
when Ractor::Port
others << arg
else
raise ArgumentError, "should be Ractor::Port or Ractor"
end
end
# One port for every watched ractor rather than one each: the exit token
# names the ractor, so there is nothing to look the result up in.
unless monitored.empty?
mp = Ractor::Port.new
monitored.each { |r| r.monitor mp }
end
if others.empty?
# Nothing but ractors: one port to wait on, so no selector is built.
token = mp.receive(timeout: timeout)
return nil if token.nil?
else
result = __builtin_ractor_select_internal(mp ? [mp, *others] : others, timeout)
return nil if result.nil?
port, obj = result
return [port, obj] unless port.equal?(mp)
token = obj
end
r = token[0]
[r, r.value]
ensure
if mp
monitored.each { |r| r.unmonitor mp }
mp.close
end
end
end
Blocks the current Thread until one of the given ports has received a message. Returns an array of two elements where the first element is the Port and the second is the received object. With timeout (in seconds) it returns nil instead once the timeout passes. This method can also accept Ractor objects themselves, and in that case will wait until one has terminated and return a two-element array where the first element is the ractor and the second is its termination value.
p1, p2 = Ractor::Port.new, Ractor::Port.new ps = [p1, p2] rs = 2.times.map do |i| Ractor.new(ps.shift, i) do |p, i| sleep rand(0.99) p.send("r#{i}") sleep rand(0.99) "r#{i} done" end end waiting_on = [p1, p2, *rs] until waiting_on.empty? received_on, obj = Ractor.select(*waiting_on) waiting_on.delete(received_on) puts obj end # r0 # r1 # r1 done # r0 done
Closing one of the given ports raises Ractor::ClosedError, whether it was closed before the call or while it waits.
The following example is almost equivalent to ractors.map(&:value) except the thread is unblocked when any of the ractors has terminated as opposed to waiting for their termination in the array element order.
values = [] until ractors.empty? r, val = Ractor.select(*ractors) ractors.delete(r) values << val end
Ruby version changes
-
4.0
-
Ractor.selectnow only accepts Ractors and Ports. If Ractors are given, it returns when aRactorterminates.
-