Project

General

Profile

Actions

Feature #17378

closed

Ractor#receive with filtering like other actor langauge

Added by ko1 (Koichi Sasada) over 3 years ago. Updated over 3 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:101317]

Description

With discussion with @marcandre (Marc-Andre Lafortune), we found good extension for Ractor.receive with block.

Ractor.receive do |msg|
  if msg is match to condition?
    true
  else
    false
  end
end

This block iterates incoming queue's values and the value is passed in msg.
If the passed value is matched you want to process, the block should return true and the value will be removed from the queue.
Otherwise (returning falsy value), the value remains in the queue, and other Ractor.receive accesses it again.
If there is not more values in queue, the interpreter sleeps until new values are received.

r = Ractor.new do |;r|
  loop do
    r, msg = Ractor.receive
    r << msg
    r << 1
    r << 2
    r << 3
  end
end

r.send([Ractor.current, :ping])

# incoming queue: [:ping, 1, 2, 3] (3 is at the last)

Ractor.receive #=> :ping # without a block

# incoming queue: [1, 2, 3]

p Ractor.receive{|msg| msg == 2}
#=> 2 

# incoming queue: [1, 3]
begin
  # exception in the block doesn't touch the queue
  p Ractor.receive{|msg| raise "err"}
rescue => e
  p e.message #=> "err"
end

# incoming queue: [1, 3]
p Ractor.receive #=> 1

# incoming queue: [3]
p Ractor.receive #=> 3

With multiple server, we can make it:

morning_server = Ractor.new do
  loop do
    task = Proc.new{|obj| "Good morning #{obj}"}
    r, req = Ractor.receive
    res = task.(req)
    r.send([Ractor.current, res])
  end
end

evening_server = Ractor.new do
  loop do
    task = Proc.new{|obj| "Good evening #{obj}"}
    r, req = Ractor.receive
    res = task.(req)
    r.send([Ractor.current, res])
  end
end

morning_server << [Ractor.current, 'ko1']
morning_server << [Ractor.current, 'ko2']
morning_server << [Ractor.current, 'ko3']

evening_server << [Ractor.current, 'ko1']
evening_server << [Ractor.current, 'ko2']
evening_server << [Ractor.current, 'ko3']

def receive r
  Ractor.receive{|(from, msg)|
    r == from
  }[1]
end

p receive(morning_server) #=> "Good morning ko1"
p receive(evening_server) #=> "Good evening ko1"
p receive(morning_server) #=> "Good morning ko2"
p receive(evening_server) #=> "Good evening ko2"
p receive(morning_server) #=> "Good morning ko3"
p receive(evening_server) #=> "Good evening ko3"

Related issues 1 (0 open1 closed)

Related to Ruby master - Feature #17365: Can not respond (well) to a Ractor ClosedActions
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0