Ractor::Selector#empty?
It returns the waiting set is empty or not. Also add Ractor::Selector's tests.
This commit is contained in:
parent
5f3c7ac196
commit
5875fce6ce
Notes:
git
2023-03-02 15:08:26 +00:00
@ -1617,4 +1617,100 @@ assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{
|
|||||||
eval("Ractor.new{}.take", nil, "test_ractor.rb", 1)
|
eval("Ractor.new{}.take", nil, "test_ractor.rb", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Ractor::Selector
|
||||||
|
|
||||||
|
# Selector#empty? returns true
|
||||||
|
assert_equal 'true', %q{
|
||||||
|
s = Ractor::Selector.new
|
||||||
|
s.empty?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selector#empty? returns false if there is target ractors
|
||||||
|
assert_equal 'false', %q{
|
||||||
|
s = Ractor::Selector.new
|
||||||
|
s.add Ractor.new{}
|
||||||
|
s.empty?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selector#clear removes all ractors from the waiting list
|
||||||
|
assert_equal 'true', %q{
|
||||||
|
s = Ractor::Selector.new
|
||||||
|
s.add Ractor.new{10}
|
||||||
|
s.add Ractor.new{20}
|
||||||
|
s.clear
|
||||||
|
s.empty?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selector#wait can wait multiple ractors
|
||||||
|
assert_equal '[10, 20, true]', %q{
|
||||||
|
s = Ractor::Selector.new
|
||||||
|
s.add Ractor.new{10}
|
||||||
|
s.add Ractor.new{20}
|
||||||
|
r, v = s.wait
|
||||||
|
vs = []
|
||||||
|
vs << v
|
||||||
|
r, v = s.wait
|
||||||
|
vs << v
|
||||||
|
[*vs.sort, s.empty?]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selector#wait can wait multiple ractors with receiving.
|
||||||
|
assert_equal '30', %q{
|
||||||
|
RN = 30
|
||||||
|
rs = RN.times.map{
|
||||||
|
Ractor.new{ :v }
|
||||||
|
}
|
||||||
|
s = Ractor::Selector.new(*rs)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
until s.empty?
|
||||||
|
results << s.wait
|
||||||
|
|
||||||
|
# Note that s.wait can raise an exception because other Ractors/Threads
|
||||||
|
# can take from the same ractors in the waiting set.
|
||||||
|
# In this case there is no other takers so `s.wait` doesn't raise an error.
|
||||||
|
end
|
||||||
|
|
||||||
|
results.size
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selector#wait can support dynamic addition
|
||||||
|
assert_equal '600', %q{
|
||||||
|
RN = 100
|
||||||
|
s = Ractor::Selector.new
|
||||||
|
rs = RN.times.map{
|
||||||
|
Ractor.new{
|
||||||
|
Ractor.main << Ractor.new{ Ractor.yield :v3; :v4 }
|
||||||
|
Ractor.main << Ractor.new{ Ractor.yield :v5; :v6 }
|
||||||
|
Ractor.yield :v1
|
||||||
|
:v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.each{|r| s.add(r)}
|
||||||
|
h = {v1: 0, v2: 0, v3: 0, v4: 0, v5: 0, v6: 0}
|
||||||
|
|
||||||
|
loop do
|
||||||
|
case s.wait receive: true
|
||||||
|
in :receive, r
|
||||||
|
s.add r
|
||||||
|
in r, v
|
||||||
|
h[v] += 1
|
||||||
|
break if h.all?{|k, v| v == RN}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
h.sum{|k, v| v}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selector should be GCed (free'ed) withtou trouble
|
||||||
|
assert_equal 'ok', %q{
|
||||||
|
RN = 30
|
||||||
|
rs = RN.times.map{
|
||||||
|
Ractor.new{ :v }
|
||||||
|
}
|
||||||
|
s = Ractor::Selector.new(*rs)
|
||||||
|
:ok
|
||||||
|
}
|
||||||
|
|
||||||
end # if !ENV['GITHUB_WORKFLOW']
|
end # if !ENV['GITHUB_WORKFLOW']
|
||||||
|
13
ractor.c
13
ractor.c
@ -1009,6 +1009,8 @@ ractor_register_take(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *t
|
|||||||
}
|
}
|
||||||
else if (!is_take && ractor_take_has_will(r)) {
|
else if (!is_take && ractor_take_has_will(r)) {
|
||||||
RUBY_DEBUG_LOG("has_will");
|
RUBY_DEBUG_LOG("has_will");
|
||||||
|
VM_ASSERT(config != NULL);
|
||||||
|
config->closed = true;
|
||||||
}
|
}
|
||||||
else if (r->sync.outgoing_port_closed) {
|
else if (r->sync.outgoing_port_closed) {
|
||||||
closed = true;
|
closed = true;
|
||||||
@ -1515,6 +1517,13 @@ ractor_selector_clear(rb_execution_context_t *ec, VALUE selv)
|
|||||||
return selv;
|
return selv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_selector_empty_p(rb_execution_context_t *ec, VALUE selv)
|
||||||
|
{
|
||||||
|
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
||||||
|
return s->take_ractors->num_entries == 0 ? Qtrue : Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t dat)
|
ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t dat)
|
||||||
{
|
{
|
||||||
@ -1687,6 +1696,10 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case basket_type_will:
|
||||||
|
// no more messages
|
||||||
|
ractor_selector_remove(ec, selv, taken_basket.sender);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
12
ractor.rb
12
ractor.rb
@ -428,6 +428,18 @@ class Ractor
|
|||||||
__builtin_ractor_selector_clear
|
__builtin_ractor_selector_clear
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# call-seq:
|
||||||
|
# selector.empty?
|
||||||
|
#
|
||||||
|
# Returns true if the number of ractors in the waiting set at the current time is zero.
|
||||||
|
#
|
||||||
|
# Note that even if <tt>#empty?</tt> returns false, the subsequent <tt>#wait</tt>
|
||||||
|
# may raise an exception because other ractors may close the target ractors.
|
||||||
|
#
|
||||||
|
def empty?
|
||||||
|
__builtin_ractor_selector_empty_p
|
||||||
|
end
|
||||||
|
|
||||||
# call-seq:
|
# call-seq:
|
||||||
# selector.wait(receive: false, yield_value: yield_value, move: false) -> [ractor or symbol, value]
|
# selector.wait(receive: false, yield_value: yield_value, move: false) -> [ractor or symbol, value]
|
||||||
#
|
#
|
||||||
|
Loading…
x
Reference in New Issue
Block a user