[#100689] [Ruby master Feature#17303] Make webrick to bundled gems or remove from stdlib — hsbt@...
Issue #17303 has been reported by hsbt (Hiroshi SHIBATA).
11 messages
2020/11/02
[#100852] [Ruby master Feature#17326] Add Kernel#must! to the standard library — zimmerman.jake@...
SXNzdWUgIzE3MzI2IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGpleiAoSmFrZSBaaW1tZXJtYW4pLg0K
24 messages
2020/11/14
[#100930] [Ruby master Feature#17333] Enumerable#many? — masafumi.o1988@...
Issue #17333 has been reported by okuramasafumi (Masafumi OKURA).
10 messages
2020/11/18
[#101071] [Ruby master Feature#17342] Hash#fetch_set — hunter_spawn@...
Issue #17342 has been reported by MaxLap (Maxime Lapointe).
26 messages
2020/11/25
[ruby-core:100713] [Ruby master Feature#17298] Ractor's basket communication APIs
From:
eregontp@...
Date:
2020-11-04 11:09:21 UTC
List:
ruby-core #100713
Issue #17298 has been updated by Eregon (Benoit Daloze).
ko1 (Koichi Sasada) wrote in #note-16:
> Eregon (Benoit Daloze) wrote in #note-15:
> > `Ractor#receive_and_sender` (aka `recvfrom` but with a proper name) and `Ractor.yield_and_sender` would be enough for that, right?
Actually it would be `Ractor#receive_with_sender` and `Ractor#take_with_sender` (or some variation, but for receive+take), my mistake
(I was thinking about Fiber.yield which also waits for a message back).
We can only know the sender when "receiving a message".
Knowing the sender when sending a message is useless, it's always Ractor.current.
> I like basket API for this purpose.
> Also we can extend the information, for example sending source location (for debugging purpose).
I see, `Ractor#receive_basket` and `Ractor#take_basket` might be nicer to get more information when receiving a message.
`send_basket` and `yield_basket` seem unnecessary, if `send/yield` already recognize it's a basket and extract the value out of it.
Or, if `send/yield` explicitly disallow sending a basket and require `ractor.yield basket.value` (since it's meaningless to pass the sender's sender there).
That would not allow the optimization, but the API feels cleaner to me that way.
A basket is then just a (value, sender) tuple, and not something that implicitly holds a serialized version of the object.
Also serializing might not have exactly the same semantics as deep copying, so it seems a risk of inconsistency, for very small performance gains.
----------------------------------------
Feature #17298: Ractor's basket communication APIs
https://bugs.ruby-lang.org/issues/17298#change-88357
* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
----------------------------------------
This ticket proposes `send_basket`/`send_receive`, `yield_basket`/`take_basket` APIs to make effective and flexible bridge ractors.
## Background
When we want to send an object as a message, we usually need to copy it. Copying is achieved according to marshal protocol, and the receiver loads it immediately.
If we want to make a bridge ractor that receives a message and sends it to another ractor, immediate loading is not effective.
```ruby
bridge = Ractor.new do
Ractor.yield Ractor.receive
end
consumer = Ractor.new bridge do |from|
obj = from.take
do_task(obj)
end
msg = [1, 2, 3]
bridge.send msg
```
In this case, the array (`[1, 2, 3]`) is
* (1) dumped at the first `bridge.send msg`
* (2) loaded at `Ractor.receive`
* (3) dumped again at `Ractor.yield`
* (4) loaded at `from.take`
Essentially, we only need one dump/load pair, but now it needs two pairs.
Mixing "moving" status is more complex. Now there is no way to pass the "moving" status to bridge ractors, so we cannot make a moving bridge.
## Proposal
To make more effective and flexible bridge ractors, we propose new basket APIs
* `Ractor.receive_basket`
* `Ractor#send_basket`
* `Ractor.take_basket`
* `Ractor.yield_basket`
They receive a message, retains the dumped state, and sends it without dumping again. We can rewrite the above example with these APIs.
```ruby
bridge = Ractor.new do
Ractor.yield_basket Ractor.receive_basket
end
consumer = Ractor.new bridge do |from|
obj = from.take
do_task(obj)
end
msg = [1, 2, 3]
bridge.send msg
```
In this case,
* (1) dumped at the first `bridge.send msg`
* (2) loaded at `from.take`
we only need one dump/load pair.
## Implementation
https://github.com/ruby/ruby/pull/3725
## Evaluation
The following program makes four types of bridges and passes an array as a message through them.
```ruby
USE_BASKET = false
receive2yield = Ractor.new do
loop do
if USE_BASKET
Ractor.yield_basket Ractor.receive_basket
else
Ractor.yield Ractor.receive
end
end
end
receive2send = Ractor.new receive2yield do |r|
loop do
if USE_BASKET
r.send_basket Ractor.receive_basket
else
r.send Ractor.receive
end
end
end
take2yield = Ractor.new receive2yield do |from|
loop do
if USE_BASKET
Ractor.yield_basket from.take_basket
else
Ractor.yield from.take
end
end
end
take2send = Ractor.new take2yield, Ractor.current do |from, to|
loop do
if USE_BASKET
to.send_basket from.take_basket
else
to.send from.take
end
end
end
AN = 1_000
LN = 10_000
ary = Array.new(AN) # 1000
LN.times{
receive2send << ary
Ractor.receive
}
# This program passes the message as:
# main ->
# receive2send ->
# receive2yield ->
# take2yield ->
# take2send ->
# main
```
The result is:
```
w/ basket API 0m2.056s
w/o basket API 0m5.974s
```
on my machine (=~ x3 faster).
(BTW, if we have a TVar, we can change the value `USE_BASKET` dynamically)
## Discussion
### Naming
Of course, naming is an issue. Now, I named it "_basket" because the source code uses this terminology. There are other candidates:
* container metaphor
* package
* parcel
* box
* envelope
* packet (maybe bad idea because of confusion of networking)
* bundle (maybe bad idea because of confusion of bin/bundle)
* "don't touch the content" metaphor
* raw
* sealed
* unopened
I like "basket" because I like picnic.
### Feature
Now, basket is represented by "Ractor::Basket" and there are no methods. We can add the following feature:
* `Ractor::Basket#sender` returns the sending ractor.
* `Ractor::Basket#sender = a_ractor` changes the sending ractor.
* `Ractor::Basket#value` returns the content.
There was another proposal `Ractor.recvfrom`, but we only need these APIs.
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>