зеркало из https://github.com/github/ruby.git
`Ractor::Selector#empty?`
It returns the waiting set is empty or not. Also add Ractor::Selector's tests.
This commit is contained in:
Родитель
5f3c7ac196
Коммит
5875fce6ce
|
@ -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)
|
||||
}
|
||||
|
||||
## 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']
|
||||
|
|
15
ractor.c
15
ractor.c
|
@ -979,7 +979,7 @@ ractor_take_will_lock(rb_ractor_t *r, struct rb_ractor_basket *b)
|
|||
|
||||
RACTOR_LOCK(r);
|
||||
{
|
||||
taken =ractor_take_will(r, b);
|
||||
taken = ractor_take_will(r, b);
|
||||
}
|
||||
RACTOR_UNLOCK(r);
|
||||
|
||||
|
@ -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)) {
|
||||
RUBY_DEBUG_LOG("has_will");
|
||||
VM_ASSERT(config != NULL);
|
||||
config->closed = true;
|
||||
}
|
||||
else if (r->sync.outgoing_port_closed) {
|
||||
closed = true;
|
||||
|
@ -1515,6 +1517,13 @@ ractor_selector_clear(rb_execution_context_t *ec, VALUE 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
|
||||
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;
|
||||
}
|
||||
case basket_type_will:
|
||||
// no more messages
|
||||
ractor_selector_remove(ec, selv, taken_basket.sender);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
12
ractor.rb
12
ractor.rb
|
@ -428,6 +428,18 @@ class Ractor
|
|||
__builtin_ractor_selector_clear
|
||||
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:
|
||||
# selector.wait(receive: false, yield_value: yield_value, move: false) -> [ractor or symbol, value]
|
||||
#
|
||||
|
|
Загрузка…
Ссылка в новой задаче