[#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

[#100715] [Ruby master Bug#17306] TestGCCompact#test_ast_compacts test failures — v.ondruch@...

Issue #17306 has been reported by vo.x (Vit Ondruch).

11 messages 2020/11/05

[#100720] [Ruby master Feature#17307] A way to mark C extensions as thread-safe, Ractor-safe, or unsafe — eregontp@...

Issue #17307 has been reported by Eregon (Benoit Daloze).

22 messages 2020/11/05

[#100744] [Ruby master Bug#17310] Closed ractors should die — marcandre-ruby-core@...

Issue #17310 has been reported by marcandre (Marc-Andre Lafortune).

12 messages 2020/11/08

[#100753] [Ruby master Feature#17312] New methods in Enumerable and Enumerator::Lazy: flatten, product, compact — zverok.offline@...

Issue #17312 has been reported by zverok (Victor Shepelev).

11 messages 2020/11/09

[#100763] [Ruby master Feature#17314] Provide a way to declare visibility of attributes defined by attr* methods in a single expression — radek.bulat@...

SXNzdWUgIzE3MzE0IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHJhZGFyZWsgKFJhZG9zxYJhdyBCdcWC

17 messages 2020/11/10

[#100777] [Ruby master Feature#17316] On memoization — sawadatsuyoshi@...

Issue #17316 has been reported by sawa (Tsuyoshi Sawada).

18 messages 2020/11/11

[#100788] [Ruby master Misc#17319] Rename Random::urandom to os_random and document random data sources — zofrex@...

Issue #17319 has been reported by zofrex (James Sanderson).

11 messages 2020/11/11

[#100807] [Ruby master Feature#17322] Deprecate `Random::DEFAULT` and introduce `Random.default()` method to provide Ractor-supported default random generator — ko1@...

Issue #17322 has been reported by ko1 (Koichi Sasada).

14 messages 2020/11/12

[#100816] [Ruby master Feature#17323] Ractor::LVar to provide ractor-local storage — ko1@...

Issue #17323 has been reported by ko1 (Koichi Sasada).

19 messages 2020/11/12

[#100849] [Ruby master Feature#17325] Adds Fiber#cancel, which forces a Fiber to break/return — nicholas.evans@...

Issue #17325 has been reported by nevans (Nicholas Evans).

17 messages 2020/11/14

[#100852] [Ruby master Feature#17326] Add Kernel#must! to the standard library — zimmerman.jake@...

SXNzdWUgIzE3MzI2IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGpleiAoSmFrZSBaaW1tZXJtYW4pLg0K

24 messages 2020/11/14

[#100858] [Ruby master Feature#17327] The Queue constructor should take an initial set of items — chris@...

Issue #17327 has been reported by chrisseaton (Chris Seaton).

10 messages 2020/11/15

[#100897] [Ruby master Feature#17330] Object#non — zverok.offline@...

Issue #17330 has been reported by zverok (Victor Shepelev).

21 messages 2020/11/17

[#100925] [Ruby master Feature#17331] Let Fiber#raise work with transferring fibers — nicholas.evans@...

Issue #17331 has been reported by nevans (Nicholas Evans).

12 messages 2020/11/18

[#100930] [Ruby master Feature#17333] Enumerable#many? — masafumi.o1988@...

Issue #17333 has been reported by okuramasafumi (Masafumi OKURA).

10 messages 2020/11/18

[#100971] [Ruby master Bug#17337] Don't embed Ruby build time configuration into Ruby — v.ondruch@...

Issue #17337 has been reported by vo.x (Vit Ondruch).

16 messages 2020/11/20

[#100999] [Ruby master Feature#17339] Semantic grouping on BigDecimal#to_s — co.chuma@...

Issue #17339 has been reported by chumaltd (Takahiro Chuma).

9 messages 2020/11/21

[#101071] [Ruby master Feature#17342] Hash#fetch_set — hunter_spawn@...

Issue #17342 has been reported by MaxLap (Maxime Lapointe).

26 messages 2020/11/25

[#101093] [Ruby master Misc#17346] DevelopersMeeting20201210Japan — mame@...

Issue #17346 has been reported by mame (Yusuke Endoh).

17 messages 2020/11/26

[#101141] [Ruby master Bug#17354] Module#const_source_location is misleading for constants awaiting autoload — tom@...

SXNzdWUgIzE3MzU0IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHRvbXN0dWFydCAoVG9tIFN0dWFydCku

21 messages 2020/11/29

[#101143] [Ruby master Feature#17355] Or-patterns (pattern matching like Foo(x) | Bar(x)) — fg@...

Issue #17355 has been reported by decuplet (Nikita Shilnikov).

8 messages 2020/11/29

[#101153] [Ruby master Feature#17356] Alignment of memory allocated through Fiddle struct's malloc — andrea.ribuoli@...

Issue #17356 has been reported by AndreaRibuoli (Andrea Ribuoli).

8 messages 2020/11/30

[ruby-core:100829] [Ruby master Feature#17100] Ractor: a proposal for a new concurrent abstraction without thread-safety issues

From: eregontp@...
Date: 2020-11-13 10:18:27 UTC
List: ruby-core #100829
Issue #17100 has been updated by Eregon (Benoit Daloze).


Thank you for the detailed explanation, that makes sense to me.
I am sure it will result in some confusion, but hopefully it will be rare in practice.

ko1 (Koichi Sasada) wrote in #note-45:
> * Matz agreed that `__send__` is ugly (*2), so he is thinking about new method dispatch operator which can replace with `__send__`.

Yes, I think that would be good.
A new module with singleton methods might be an elegant way to make some basic methods which must not be redefined available.
That module could just be frozen to avoid redefinitions (the constant could still be re-assigned, but we could explicitly raise/warn against it).

I find it interesting that so far we only needed a non-redefined variant for `send` (`__send__`) and `object_id` (`__id__`), and not other Kernel/Object/BasicObject methods.
And in practice it seems very rare to override `object_id`, so it seems it's really just `send` being overridden for unrelated semantics.
I see it as the Liskov's substitution principle being mostly respected.

BTW, any `initialize` method is a superset of/is compatible with `BasicObject#initialize`, since that does nothing.

> `post(obj)`: I can't accept this method name because it is strongly connected with mailing system. (and other names)

Isn't it common actor terminology to receive a message in a *mailbox*? (e.g. https://erlang.org/doc/reference_manual/processes.html)
So I think the connection to mailing has been for a while.

----------------------------------------
Feature #17100: Ractor: a proposal for a new concurrent abstraction without thread-safety issues
https://bugs.ruby-lang.org/issues/17100#change-88469

* Author: ko1 (Koichi Sasada)
* Status: Closed
* Priority: Normal
* Assignee: ko1 (Koichi Sasada)
----------------------------------------
# Ractor: a proposal for a new concurrent abstraction without thread-safety issues

## Abstract

This ticket proposes a new concurrent abstraction named "Ractor," Ruby's Actor-like feature (not an exact Actor-model).

Ractor achieves the following goals:

* Parallel execution in a Ruby interpreter process
* Avoidance of thread-safety issues (especially race issues) by limiting object sharing
* Communication via copying and moving

I have been working on this proposal for a few years. The project name has been "Guild," but I renamed it to Ractor following Matz' preference.

Resources:
* Proposed specification: https://github.com/ko1/ruby/blob/ractor_parallel/doc/ractor.md
* My talk:
  * (latest, but written in Japanese) http://atdot.net/~ko1/activities/2020_ruby3summit.pdf
  * (old, API is changed) http://atdot.net/~ko1/activities/2018_rubykaigi2018.pdf
  * (old, API is changed) http://atdot.net/~ko1/activities/2018_rubyconf2018.pdf

Current implementation is not complete (contains many bugs) but it passes the current CI. I propose to merge it soon and try the API, and to continue working on the implementation on master branch.

## Background

MRI doesn't provide an in-process parallel computation feature because parallel "Threads" have many issues:

* Ruby programmers need to consider about Thread-safety more.
* Interpreter developers need to consider about Thread-safety more.
* Interpreter will slow down in single thread execution because of fine-grain synchronization without clever optimizations.

The reason for these issues is "shared-everything" thread model.

## Proposal

To overcome the issues on multiple-threads, Ractor abstraction is proposed. This proposal consists of two layers: memory model and communication model.

Basics:
* Introduce "Ractor" as a new concurrent entity.
* Ractors run in parallel.

Memory model:
* Separate "shareable" objects and "un-shareable" objects among ractors running in parallel.
   * Shareable objects:
     * Immutable objects (frozen objects only refer to shareable objects)
     * Class/module objects
     * Special shareable objects (Ractor objects, and so on)
   * Un-shareable objects: 
     * Other objects
* Most objects are "un-shareable," which means we Ruby programmers and interpreter developers don't need to care about thread-safety in most cases.
* We only concentrate on synchronizing "shareable" objects.
* Compared with completely separated memory model (like MVM proposal), programming will be easier.
* This model is similar to Racket's `Place` abstraction.

Communication model:
* Actor-like (not the same) message passing using `Ractor#send(obj)` and `Ractor.recv`
* Pull-type communication using `Ractor.yield(obj)` and `Ractor#take`
* Support for multiple waiting using `Ractor.select(...)`

Actor-like model is the origin of the name of our proposal "Ractor" (Ruby's actor). However, currently, it is not an Actor model because we can't select the message (using pattern match as in Erlang, Elixir, ...). This means that we can't have multiple communication channels. Instead of adopting an incomplete actor model, this proposal provides `yield`/`take` pair to handle multiple channels. We discuss this topic later.

I strongly believe the memory model is promising. However, I'm not sure if the communication model is the best. This is why I introduced "experimental" warning.

Proposed specification: https://github.com/ko1/ruby/blob/ractor_parallel/doc/ractor.md

## Implementation

https://github.com/ruby/ruby/pull/3365
All GH actions pass.

I describe the implementation briefly.

### `rb_ractor_t`

Without Ractor, the VM-Thread-Fiber hierarchy is like this:

* The VM `rb_vm_t` manages running threads (`rb_thread_t`).
* A thread (`rb_thread_t`) points to a running fiber (`rb_fiber_t`).

With Ractor, we introduce a new layer `rb_ractor_t`:

* The VM `rb_vm_t` manages running ractors (`rb_ractor_t`).
* A Ractor manages running threads (`rb_thread_t`).
* A thread (`rb_thread_t`) points to a running fiber (`rb_fiber_t`).

`rb_ractor_t` has a GVL to manage threads (only one among a Ractor's threads can run).

Ractor implementation is located in `ractor.h`, `ractor.c` and `ractor.rb`.

### VM-wide lock

VM-wide lock is introduced to protect VM global resources such as object space. It should allow recursive lock, so the implementation is a monitor. We shall call it VM-wide monitor. For now, `RB_VM_LOCK_ENTER()` and `RB_VM_LOCK_LEAVE()` are provided to acquire/release the lock.

Note that it is different from the (current) GVL. A GVL is acquired anytime you run a Ruby thread. VM-wide lock is acquired only when accessing VM-wide resources.

On single ractor mode (all Ruby scripts except my tests) 

### Object management and GC

* (1) All ractors share the object space.
* (2) Each GC event will stop all ractors, and a ractor GC works under barrier synchronization.
  * Barrier at `gc_enter()`
  * marking, (lazy) sweeping, ...
* (3) Because all of the object space are shared by ractors, object creation is protected by VM-wide lock.

(2) and (3) have huge impact on performance. The plan is:

* For (2), introduce (semi-)separated object space. It would require a long time and Ruby 3.0 can't employ this technique.
* For (3), introduce free slot cache for every ractor; then most creations can be done without synchronization. It will be employed soon.

### Experimental warning

Currently, Ractor implementation and specification are not stable. So upon its first usage, `Ractor.new` will show a warning:

`warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.`

## Discussion

### Actor-based and channel-based

I think there are two message passing approaches: Actor-based (as in Erlang, ...) and channel-based (as in Go, ...).

With channel-based approach, it is easy to manipulate multiple channels because it manages them explicitly. Actor-based approach manipulates multiple channels with message pattern. The receiver can ignore unexpected structured messages or put them on hold and can handle them after the behavior has changed (role of actor has changed).

Ractor has `send/recv` like Actor-model, but there is no pattern matching feature. This is because we can't introduce new syntax, and I can't design a good API.

With channel-based approach, it is easy to design the API (for example, do `ch = Ractor::Channel.new` and share the `ch` that ractors can provide). However, I can't design a good API to handle exceptions among Ractors.

Regarding error handling, we propose a hybrid model using `send/recv`, `yield/take` pairs. `Ractor#take` can receive the source ractor's exception (like `Thread#join`). On Actor approach, we can detect when the destination Ractor is not working (killed) upon `Ractor#send(obj)`. A receiver ractor (waiting for `Ractor.recv`) cannot detect the sender's trouble, but maybe the priority is not high. `Ractor#take` also detects the sender's (`Ractor.yield(obj)`) error, so the error can be propagated.

To handle multiple communication channels on Ractor, instead of using multiple channels, we use *pipe* ractors.

```
# worker-pool (receive by send)

main # pipe.send(obj)
-> pipe # Ractor.yield Ractor.recv
  ->
    worker1 # Ractor.yield(some_task pipe.take))
    worker2 # Ractor.yield(some_task pipe.take))
    worker3 # Ractor.yield(some_task pipe.take))
-> main # Ractor.select(worker1, worker2, worker3)

# if worker* causes an error, main can detect the error.
```

*pipe* ractors may look like channels. However, we don't need to introduce new classes with this technique (the implementation can omit Ractor creation for pipe ractors).

Maybe there are other possibilities. For example, if we can propagate the errors with channels, we can also consider a channel-model (we need to change the Ractor name :p then).

### Name of Ractor (and Guild)

When I proposed Guild in 2016, I regarded "move" message-passing (see specification) to be characteristic of it, and I called this feature "moving membership." This is why the name "Guild" was chosen. However Matz pointed out that this move semantics is not used frequently, and he asked me to change the name. Also, someone had already been using the class name "Guild."

"Ractor" is short and is not an existing class; this is why I choose "Ractor."

I understand people may confuse it with "Reactor."

## TODO

There are many remaining tasks.

### Protection

Many VM-wide (process-wide) resources are not protected correctly, so using Ractor on a complicated program can cause critical bugs (`[BUG]`). Most global resource are managed by global variables, so we need to check them correctly.

### C-methods

Currently, C-methods (methods written in C and defined with `rb_define_method()`) run in parallel. It means that thread-unsafe code can run in parallel. To solve this issue, I plan the following:

(1) Introduce thread-unsafe label for methods

It is impossible to make all C-methods thread-safe, especially for C-methods in third party C-extensions. To protect them, label these (possibly) thread-unsafe C-methods as "thread-unsafe."

When "unsafe"-labeled C methods are invoked, they acquire a VM-wide lock. This VM-wide lock should check for recursiveness (so this lock should be a monitor) and escaping (exceptions). Currently, VM-wide lock doesn't check for escaping, but that should be implemented soon.

(2) Built-in C-methods

I'll fix most of the builtin C-methods (String, Array, ...) so that they will become thread-safe. If it is not easy, I'll use thread-unsafe label.

### Copying and moving

Currently, Marshal protocol makes deep copy on message communication. However, Marshal protocol doesn't support some objects like `Ractor` objects, so we need to modify them.

Only a few types are supported for moving, so we need to write more.

### "GVL" naming

Currently, the source code contains the name "GVL" for Ractor local locks. Maybe they should be renamed.

### Performance

To introduce fine-grained lock, performance tuning is needed.

### Bug fixes

many many ....

## Conclusion

This ticket proposes a new concurrent abstraction "Ractor." I think Ruby 3 can ship with Ractor under "experimental" status.




-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread