Skip to content

Instantly share code, notes, and snippets.

@seki
Created January 3, 2026 02:19
Show Gist options
  • Select an option

  • Save seki/784c839af1b392055e93806ddba3fc2a to your computer and use it in GitHub Desktop.

Select an option

Save seki/784c839af1b392055e93806ddba3fc2a to your computer and use it in GitHub Desktop.
Ractor study. NQueen with tuplespace.
require 'rinda/tuplespace'
class TupleSpace4Ractor
class Impl
def initialize
@ts = Rinda::TupleSpace.new #FIXME
@read_waiter = []
@take_waiter = []
end
def do_take(port, pattern)
tuple = @ts.take(pattern, 0)
port << tuple
true
rescue Rinda::RequestExpiredError
false
end
def do_read(port, pattern)
tuple = @ts.read(pattern, 0)
port << tuple
true
rescue Rinda::RequestExpiredError
false
end
def do_write(tuple)
@ts.write(tuple)
@read_waiter.delete_if {|port, pattern| do_read(port, pattern)}
taken = false
@take_waiter.delete_if {|port, pattern|
break if taken
taken = do_take(port, pattern)
}
end
def main_loop
while true
command, tuple, port = Ractor.receive
case command
when :read
@read_waiter << [port, tuple] unless do_read(port, tuple)
when :take
@take_waiter << [port, tuple] unless do_take(port, tuple)
when :write
do_write(tuple)
end
end
end
end
def initialize
@ractor = Ractor.new { Impl.new.main_loop }
end
def take(pattern)
port = Ractor::Port.new
@ractor << [:take, pattern, port]
port.receive
end
def read(pattern)
port = Ractor::Port.new
@ractor << [:read, pattern, port]
port.receive
end
def write(tuple)
@ractor << [:write, tuple]
nil
end
end
module NQueen
module_function
def concat(board, row)
board.each_with_index do |v, col|
check = (v - row).abs
return nil if check == 0
return nil if check == board.size - col
end
board + [row]
end
def nq(size, board=[])
found = 0
size.times do |row|
fwd = concat(board, row)
next unless fwd
return 1 if fwd.size == size
found += nq(size, fwd)
end
found
end
def nq2(size, r1, r2)
board = concat([r1], r2)
return 0 unless board
nq(size, board)
end
end
def invoke_engine(rinda, num)
num.times do
Ractor.new(rinda) do |ts|
while true
sym, size, r1, r2 = ts.take([:nq, Integer, Integer, Integer])
ts.write([:nq_ans, size, r1, r2, NQueen.nq2(size, r1, r2)])
end
ts.write([:nq_engine])
end
end
end
def write_q(rinda, size)
size.times do |r1|
size.times do |r2|
rinda.write([:nq, size, r1, r2])
end
end
end
def take_a(rinda, size)
found = 0
size.times do |r1|
size.times do |r2|
tuple = rinda.take([:nq_ans, size, r1, r2, nil])
found += tuple[4]
end
end
found
end
def resolve(rinda, size)
write_q(rinda, size)
take_a(rinda, size)
end
rinda = TupleSpace4Ractor.new
size = (ARGV.shift || '5').to_i
invoke_engine(rinda, 8)
puts resolve(rinda, size)
exit!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment