Project

General

Profile

Feature #17378

Updated by Eregon (Benoit Daloze) over 3 years ago

With discussion with @marcandre, we found good extension for `Ractor.receive` with block. 

 ```ruby 
 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 falthy 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. 

 ```ruby 
 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: 

 ```ruby 
 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" 
 ``` 

Back