remove Ractor::Selector
from Ruby level
`Ractor::Selector` is not approved by Matz so remove it from Ruby-level. The implementation is used by `Ractor.select` so most of implementation was remaind and calling `rb_init_ractor_selector()`, `Ractor::Selector` will be defined. I will provide `ractor-selector` gem to try it.
This commit is contained in:
parent
9b4cb69a88
commit
c9a9b8036c
@ -1401,7 +1401,7 @@ assert_equal '[false, false, true, true]', %q{
|
|||||||
}
|
}
|
||||||
|
|
||||||
# TracePoint with normal Proc should be Ractor local
|
# TracePoint with normal Proc should be Ractor local
|
||||||
assert_equal '[4, 8]', %q{
|
assert_equal '[6, 10]', %q{
|
||||||
rs = []
|
rs = []
|
||||||
TracePoint.new(:line){|tp| rs << tp.lineno if tp.path == __FILE__}.enable do
|
TracePoint.new(:line){|tp| rs << tp.lineno if tp.path == __FILE__}.enable do
|
||||||
Ractor.new{ # line 4
|
Ractor.new{ # line 4
|
||||||
@ -1647,12 +1647,16 @@ assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{
|
|||||||
|
|
||||||
# Selector#empty? returns true
|
# Selector#empty? returns true
|
||||||
assert_equal 'true', %q{
|
assert_equal 'true', %q{
|
||||||
|
skip true unless defined? Ractor::Selector
|
||||||
|
|
||||||
s = Ractor::Selector.new
|
s = Ractor::Selector.new
|
||||||
s.empty?
|
s.empty?
|
||||||
}
|
}
|
||||||
|
|
||||||
# Selector#empty? returns false if there is target ractors
|
# Selector#empty? returns false if there is target ractors
|
||||||
assert_equal 'false', %q{
|
assert_equal 'false', %q{
|
||||||
|
skip false unless defined? Ractor::Selector
|
||||||
|
|
||||||
s = Ractor::Selector.new
|
s = Ractor::Selector.new
|
||||||
s.add Ractor.new{}
|
s.add Ractor.new{}
|
||||||
s.empty?
|
s.empty?
|
||||||
@ -1660,6 +1664,8 @@ assert_equal 'false', %q{
|
|||||||
|
|
||||||
# Selector#clear removes all ractors from the waiting list
|
# Selector#clear removes all ractors from the waiting list
|
||||||
assert_equal 'true', %q{
|
assert_equal 'true', %q{
|
||||||
|
skip true unless defined? Ractor::Selector
|
||||||
|
|
||||||
s = Ractor::Selector.new
|
s = Ractor::Selector.new
|
||||||
s.add Ractor.new{10}
|
s.add Ractor.new{10}
|
||||||
s.add Ractor.new{20}
|
s.add Ractor.new{20}
|
||||||
@ -1669,6 +1675,8 @@ assert_equal 'true', %q{
|
|||||||
|
|
||||||
# Selector#wait can wait multiple ractors
|
# Selector#wait can wait multiple ractors
|
||||||
assert_equal '[10, 20, true]', %q{
|
assert_equal '[10, 20, true]', %q{
|
||||||
|
skip [10, 20, true] unless defined? Ractor::Selector
|
||||||
|
|
||||||
s = Ractor::Selector.new
|
s = Ractor::Selector.new
|
||||||
s.add Ractor.new{10}
|
s.add Ractor.new{10}
|
||||||
s.add Ractor.new{20}
|
s.add Ractor.new{20}
|
||||||
@ -1678,10 +1686,12 @@ assert_equal '[10, 20, true]', %q{
|
|||||||
r, v = s.wait
|
r, v = s.wait
|
||||||
vs << v
|
vs << v
|
||||||
[*vs.sort, s.empty?]
|
[*vs.sort, s.empty?]
|
||||||
}
|
} if defined? Ractor::Selector
|
||||||
|
|
||||||
# Selector#wait can wait multiple ractors with receiving.
|
# Selector#wait can wait multiple ractors with receiving.
|
||||||
assert_equal '30', %q{
|
assert_equal '30', %q{
|
||||||
|
skip 30 unless defined? Ractor::Selector
|
||||||
|
|
||||||
RN = 30
|
RN = 30
|
||||||
rs = RN.times.map{
|
rs = RN.times.map{
|
||||||
Ractor.new{ :v }
|
Ractor.new{ :v }
|
||||||
@ -1698,11 +1708,13 @@ assert_equal '30', %q{
|
|||||||
end
|
end
|
||||||
|
|
||||||
results.size
|
results.size
|
||||||
}
|
} if defined? Ractor::Selector
|
||||||
|
|
||||||
# Selector#wait can support dynamic addition
|
# Selector#wait can support dynamic addition
|
||||||
yjit_enabled = ENV.key?('RUBY_YJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('yjit') || BT.ruby.include?('yjit')
|
yjit_enabled = ENV.key?('RUBY_YJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('yjit') || BT.ruby.include?('yjit')
|
||||||
assert_equal '600', %q{
|
assert_equal '600', %q{
|
||||||
|
skip 600 unless defined? Ractor::Selector
|
||||||
|
|
||||||
RN = 100
|
RN = 100
|
||||||
s = Ractor::Selector.new
|
s = Ractor::Selector.new
|
||||||
rs = RN.times.map{
|
rs = RN.times.map{
|
||||||
@ -1732,6 +1744,8 @@ assert_equal '600', %q{
|
|||||||
|
|
||||||
# Selector should be GCed (free'ed) without trouble
|
# Selector should be GCed (free'ed) without trouble
|
||||||
assert_equal 'ok', %q{
|
assert_equal 'ok', %q{
|
||||||
|
skip :ok unless defined? Ractor::Selector
|
||||||
|
|
||||||
RN = 30
|
RN = 30
|
||||||
rs = RN.times.map{
|
rs = RN.times.map{
|
||||||
Ractor.new{ :v }
|
Ractor.new{ :v }
|
||||||
|
113
ractor.c
113
ractor.c
@ -1476,10 +1476,10 @@ RACTOR_SELECTOR_PTR(VALUE selv)
|
|||||||
// Ractor::Selector.new
|
// Ractor::Selector.new
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ractor_selector_create(VALUE crv)
|
ractor_selector_create(VALUE klass)
|
||||||
{
|
{
|
||||||
struct rb_ractor_selector *s;
|
struct rb_ractor_selector *s;
|
||||||
VALUE selv = TypedData_Make_Struct(rb_cRactorSelector, struct rb_ractor_selector, &ractor_selector_data_type, s);
|
VALUE selv = TypedData_Make_Struct(klass, struct rb_ractor_selector, &ractor_selector_data_type, s);
|
||||||
s->take_basket.type.e = basket_type_reserved;
|
s->take_basket.type.e = basket_type_reserved;
|
||||||
s->take_ractors = st_init_numtable(); // ractor (ptr) -> take_config
|
s->take_ractors = st_init_numtable(); // ractor (ptr) -> take_config
|
||||||
return selv;
|
return selv;
|
||||||
@ -1488,7 +1488,7 @@ ractor_selector_create(VALUE crv)
|
|||||||
// Ractor::Selector#add(r)
|
// Ractor::Selector#add(r)
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
|
ractor_selector_add(VALUE selv, VALUE rv)
|
||||||
{
|
{
|
||||||
if (!rb_ractor_p(rv)) {
|
if (!rb_ractor_p(rv)) {
|
||||||
rb_raise(rb_eArgError, "Not a ractor object");
|
rb_raise(rb_eArgError, "Not a ractor object");
|
||||||
@ -1506,7 +1506,7 @@ ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
|
|||||||
config->closed = false;
|
config->closed = false;
|
||||||
config->oneshot = false;
|
config->oneshot = false;
|
||||||
|
|
||||||
if (ractor_register_take(rb_ec_ractor_ptr(ec), r, &s->take_basket, false, config, true)) {
|
if (ractor_register_take(GET_RACTOR(), r, &s->take_basket, false, config, true)) {
|
||||||
st_insert(s->take_ractors, (st_data_t)r, (st_data_t)config);
|
st_insert(s->take_ractors, (st_data_t)r, (st_data_t)config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1516,7 +1516,7 @@ ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
|
|||||||
// Ractor::Selector#remove(r)
|
// Ractor::Selector#remove(r)
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ractor_selector_remove(rb_execution_context_t *ec, VALUE selv, VALUE rv)
|
ractor_selector_remove(VALUE selv, VALUE rv)
|
||||||
{
|
{
|
||||||
if (!rb_ractor_p(rv)) {
|
if (!rb_ractor_p(rv)) {
|
||||||
rb_raise(rb_eArgError, "Not a ractor object");
|
rb_raise(rb_eArgError, "Not a ractor object");
|
||||||
@ -1549,28 +1549,24 @@ struct ractor_selector_clear_data {
|
|||||||
static int
|
static int
|
||||||
ractor_selector_clear_i(st_data_t key, st_data_t val, st_data_t data)
|
ractor_selector_clear_i(st_data_t key, st_data_t val, st_data_t data)
|
||||||
{
|
{
|
||||||
struct ractor_selector_clear_data *ptr = (struct ractor_selector_clear_data *)data;
|
VALUE selv = (VALUE)data;
|
||||||
rb_ractor_t *r = (rb_ractor_t *)key;
|
rb_ractor_t *r = (rb_ractor_t *)key;
|
||||||
ractor_selector_remove(ptr->ec, ptr->selv, r->pub.self);
|
ractor_selector_remove(selv, r->pub.self);
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ractor_selector_clear(rb_execution_context_t *ec, VALUE selv)
|
ractor_selector_clear(VALUE selv)
|
||||||
{
|
{
|
||||||
struct ractor_selector_clear_data data = {
|
|
||||||
.selv = selv,
|
|
||||||
.ec = ec,
|
|
||||||
};
|
|
||||||
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
||||||
|
|
||||||
st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)&data);
|
st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)selv);
|
||||||
st_clear(s->take_ractors);
|
st_clear(s->take_ractors);
|
||||||
return selv;
|
return selv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ractor_selector_empty_p(rb_execution_context_t *ec, VALUE selv)
|
ractor_selector_empty_p(VALUE selv)
|
||||||
{
|
{
|
||||||
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
||||||
return s->take_ractors->num_entries == 0 ? Qtrue : Qfalse;
|
return s->take_ractors->num_entries == 0 ? Qtrue : Qfalse;
|
||||||
@ -1642,8 +1638,9 @@ ractor_selector_wait_cleaup(rb_ractor_t *cr, void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
|
ractor_selector__wait(VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
|
||||||
{
|
{
|
||||||
|
rb_execution_context_t *ec = GET_EC();
|
||||||
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
|
||||||
struct rb_ractor_basket *tb = &s->take_basket;
|
struct rb_ractor_basket *tb = &s->take_basket;
|
||||||
struct rb_ractor_basket taken_basket;
|
struct rb_ractor_basket taken_basket;
|
||||||
@ -1739,7 +1736,7 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
|
|||||||
case basket_type_yielding:
|
case basket_type_yielding:
|
||||||
rb_bug("unreachable");
|
rb_bug("unreachable");
|
||||||
case basket_type_deleted: {
|
case basket_type_deleted: {
|
||||||
ractor_selector_remove(ec, selv, taken_basket.sender);
|
ractor_selector_remove(selv, taken_basket.sender);
|
||||||
|
|
||||||
rb_ractor_t *r = RACTOR_PTR(taken_basket.sender);
|
rb_ractor_t *r = RACTOR_PTR(taken_basket.sender);
|
||||||
if (ractor_take_will_lock(r, &taken_basket)) {
|
if (ractor_take_will_lock(r, &taken_basket)) {
|
||||||
@ -1755,7 +1752,7 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
|
|||||||
}
|
}
|
||||||
case basket_type_will:
|
case basket_type_will:
|
||||||
// no more messages
|
// no more messages
|
||||||
ractor_selector_remove(ec, selv, taken_basket.sender);
|
ractor_selector_remove(selv, taken_basket.sender);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1769,6 +1766,60 @@ ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev,
|
|||||||
return rb_ary_new_from_args(2, ret_r, ret_v);
|
return rb_ary_new_from_args(2, ret_r, ret_v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_selector_wait(int argc, VALUE *argv, VALUE selector)
|
||||||
|
{
|
||||||
|
VALUE options;
|
||||||
|
ID keywords[3];
|
||||||
|
VALUE values[3];
|
||||||
|
|
||||||
|
keywords[0] = rb_intern("receive");
|
||||||
|
keywords[1] = rb_intern("yield_value");
|
||||||
|
keywords[2] = rb_intern("move");
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "0:", &options);
|
||||||
|
rb_get_kwargs(options, keywords, 0, numberof(values), values);
|
||||||
|
return ractor_selector__wait(selector,
|
||||||
|
values[0] == Qundef ? Qfalse : RTEST(values[0]),
|
||||||
|
values[1] != Qundef, values[1], values[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_selector_new(int argc, VALUE *ractors, VALUE klass)
|
||||||
|
{
|
||||||
|
VALUE selector = ractor_selector_create(klass);
|
||||||
|
|
||||||
|
for (int i=0; i<argc; i++) {
|
||||||
|
ractor_selector_add(selector, ractors[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_select_internal(rb_execution_context_t *ec, VALUE self, VALUE ractors, VALUE do_receive, VALUE do_yield, VALUE yield_value, VALUE move)
|
||||||
|
{
|
||||||
|
VALUE selector = ractor_selector_new(RARRAY_LENINT(ractors), (VALUE *)RARRAY_CONST_PTR(ractors), rb_cRactorSelector);
|
||||||
|
VALUE result;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
EC_PUSH_TAG(ec);
|
||||||
|
if ((state = EC_EXEC_TAG() == TAG_NONE)) {
|
||||||
|
result = ractor_selector__wait(selector, do_receive, do_yield, yield_value, move);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ensure
|
||||||
|
ractor_selector_clear(selector);
|
||||||
|
|
||||||
|
// jump
|
||||||
|
EC_JUMP_TAG(ec, state);
|
||||||
|
}
|
||||||
|
EC_POP_TAG();
|
||||||
|
|
||||||
|
RB_GC_GUARD(ractors);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Ractor#close_incoming
|
// Ractor#close_incoming
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
@ -2439,6 +2490,29 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
|
|||||||
rb_raise(rb_eRactorMovedError, "can not send any methods to a moved object");
|
rb_raise(rb_eRactorMovedError, "can not send any methods to a moved object");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_RACTOR_SELECTOR
|
||||||
|
#define USE_RACTOR_SELECTOR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RUBY_SYMBOL_EXPORT_BEGIN
|
||||||
|
void rb_init_ractor_selector(void);
|
||||||
|
RUBY_SYMBOL_EXPORT_END
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_init_ractor_selector(void)
|
||||||
|
{
|
||||||
|
rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
|
||||||
|
rb_undef_alloc_func(rb_cRactorSelector);
|
||||||
|
|
||||||
|
rb_define_singleton_method(rb_cRactorSelector, "new", ractor_selector_new , -1);
|
||||||
|
rb_define_method(rb_cRactorSelector, "add", ractor_selector_add, 1);
|
||||||
|
rb_define_method(rb_cRactorSelector, "remove", ractor_selector_remove, 1);
|
||||||
|
rb_define_method(rb_cRactorSelector, "clear", ractor_selector_clear, 0);
|
||||||
|
rb_define_method(rb_cRactorSelector, "empty?", ractor_selector_empty_p, 0);
|
||||||
|
rb_define_method(rb_cRactorSelector, "wait", ractor_selector_wait, -1);
|
||||||
|
rb_define_method(rb_cRactorSelector, "_wait", ractor_selector__wait, 4);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Document-class: Ractor::ClosedError
|
* Document-class: Ractor::ClosedError
|
||||||
*
|
*
|
||||||
@ -2559,8 +2633,9 @@ Init_Ractor(void)
|
|||||||
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
|
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
|
||||||
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
|
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
|
||||||
|
|
||||||
rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
|
#if USE_RACTOR_SELECTOR
|
||||||
rb_undef_alloc_func(rb_cRactorSelector);
|
rb_init_ractor_selector();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
126
ractor.rb
126
ractor.rb
@ -358,129 +358,13 @@ class Ractor
|
|||||||
def self.select(*ractors, yield_value: yield_unspecified = true, move: false)
|
def self.select(*ractors, yield_value: yield_unspecified = true, move: false)
|
||||||
raise ArgumentError, 'specify at least one ractor or `yield_value`' if yield_unspecified && ractors.empty?
|
raise ArgumentError, 'specify at least one ractor or `yield_value`' if yield_unspecified && ractors.empty?
|
||||||
|
|
||||||
begin
|
if ractors.delete Ractor.current
|
||||||
if ractors.delete Ractor.current
|
do_receive = true
|
||||||
do_receive = true
|
else
|
||||||
else
|
do_receive = false
|
||||||
do_receive = false
|
|
||||||
end
|
|
||||||
selector = Ractor::Selector.new(*ractors)
|
|
||||||
|
|
||||||
if yield_unspecified
|
|
||||||
selector.wait receive: do_receive
|
|
||||||
else
|
|
||||||
selector.wait receive: do_receive, yield_value: yield_value, move: move
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
selector.clear
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Ractor::Selector provides a functionality to wait multiple Ractor events.
|
|
||||||
# Ractor::Selector#wait is more lightweight than Ractor.select()
|
|
||||||
# because we don't have to specify all target ractors for each wait time.
|
|
||||||
#
|
|
||||||
# Ractor.select() uses Ractor::Selector internally to implement it.
|
|
||||||
#
|
|
||||||
class Selector
|
|
||||||
# call-seq:
|
|
||||||
# Ractor::Selector.new(*ractors)
|
|
||||||
#
|
|
||||||
# Creates a selector object.
|
|
||||||
#
|
|
||||||
# If a ractors parameter is given, it is same as the following code.
|
|
||||||
#
|
|
||||||
# selector = Ractor::Selector.new
|
|
||||||
# ractors.each{|r| selector.add r}
|
|
||||||
#
|
|
||||||
def self.new(*rs)
|
|
||||||
selector = __builtin_cexpr! %q{
|
|
||||||
ractor_selector_create(self);
|
|
||||||
}
|
|
||||||
rs.each{|r| selector.add(r) }
|
|
||||||
selector
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# call-seq:
|
__builtin_ractor_select_internal ractors, do_receive, !yield_unspecified, yield_value, move
|
||||||
# selector.add(ractor)
|
|
||||||
#
|
|
||||||
# Registers a ractor as a taking target by the selector.
|
|
||||||
#
|
|
||||||
def add r
|
|
||||||
__builtin_ractor_selector_add r
|
|
||||||
end
|
|
||||||
|
|
||||||
# call-seq:
|
|
||||||
# selector.remove(ractor)
|
|
||||||
#
|
|
||||||
# Deregisters a ractor as a taking target by the selector.
|
|
||||||
#
|
|
||||||
def remove r
|
|
||||||
__builtin_ractor_selector_remove r
|
|
||||||
end
|
|
||||||
|
|
||||||
# call-seq:
|
|
||||||
# selector.clear
|
|
||||||
#
|
|
||||||
# Deregisters all ractors.
|
|
||||||
def clear
|
|
||||||
__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]
|
|
||||||
#
|
|
||||||
# Waits Ractor events. It is lighter than Ractor.select() for many ractors.
|
|
||||||
#
|
|
||||||
# The simplest form is waiting for taking a value from one of
|
|
||||||
# registerred ractors like that.
|
|
||||||
#
|
|
||||||
# selector = Ractor::Selector.new(r1, r2, r3)
|
|
||||||
# r, v = selector.wait
|
|
||||||
#
|
|
||||||
# On this case, when r1, r2 or r3 is ready to take (yielding a value),
|
|
||||||
# this method takes the value from the ready (yielded) ractor
|
|
||||||
# and returns [the yielded ractor, the taking value].
|
|
||||||
#
|
|
||||||
# Note that if a take target ractor is closed, the ractor will be removed
|
|
||||||
# automatically.
|
|
||||||
#
|
|
||||||
# If you also want to wait with receiving an object from other ractors,
|
|
||||||
# you can specify receive: true keyword like:
|
|
||||||
#
|
|
||||||
# r, v = selector.wait receive: true
|
|
||||||
#
|
|
||||||
# On this case, wait for taking from r1, r2 or r3 and waiting for receving
|
|
||||||
# a value from other ractors.
|
|
||||||
# If it successes the receiving, it returns an array object [:receive, the received value].
|
|
||||||
#
|
|
||||||
# If you also want to wait with yielding a value, you can specify
|
|
||||||
# :yield_value like:
|
|
||||||
#
|
|
||||||
# r, v = selector.wait yield_value: obj
|
|
||||||
#
|
|
||||||
# On this case wait for taking from r1, r2, or r3 and waiting for taking
|
|
||||||
# yielding value (obj) by another ractor.
|
|
||||||
# If antoher ractor takes the value (obj), it returns an array object [:yield, nil].
|
|
||||||
#
|
|
||||||
# You can specify a keyword parameter <tt>move: true</tt> like Ractor.yield(obj, move: true)
|
|
||||||
#
|
|
||||||
def wait receive: false, yield_value: yield_unspecified = true, move: false
|
|
||||||
__builtin_ractor_selector_wait receive, !yield_unspecified, yield_value, move
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
Loading…
x
Reference in New Issue
Block a user