From: "forthoney (Seong-Heon Jung) via ruby-core" Date: 2024-02-19T18:20:16+00:00 Subject: [ruby-core:116850] [Ruby master Feature#20276] Introduce Fiber interfaces for Blocking operations on Ractors Issue #20276 has been updated by forthoney (Seong-Heon Jung). ko1 (Koichi Sasada) wrote in #note-2: > I understand the motivation but now the ractor-thread combination is not well-defined yet and combination with Fiber (scheduler) is also earlier (because of Ractor's specification and implementation). I actually tried writing out some code to picture how this might be implemented, and I understand the complexity now. In the current implementation `rb_fiber_scheduler_block/unblock`, if `ractor_a` were to call `ractor_b.take` we would need the following process: 1. `ractor_a` emits `block` event to `ractor_a`'s scheduler 2. `ractor_a`'s current fiber yields, and different fiber runs on `ractor_a` 3. `ractor_b` calls yield 4. `ractor_b` emits `unblock` event to **`ractor_a`**'s scheduler With the strict object sharing rules between ractors, I can see why it may require a major rewrite to make Ractor blocking operations a fiber-scheduler event. How is this alternative? Instead of relying on automatic scheduling via Fiber scheduler events, we can rely a bit on programmer intervention. If there is a method like `Ractor#take_nonblock` which works similar to `IO#read_nonblock`, the programmer can write code like ```ruby loop do msg = other_ractor.take_nonblock rescue Errno::EAGAIN task.yield retry end ``` This may not be 100% efficient since the scheduler would need to continuously "ask", but better than this not being possible at all. ---------------------------------------- Feature #20276: Introduce Fiber interfaces for Blocking operations on Ractors https://bugs.ruby-lang.org/issues/20276#change-106881 * Author: forthoney (Seong-Heon Jung) * Status: Feedback * Priority: Normal ---------------------------------------- ### Motivation I am trying to build a web server with Ractors. The lifecycle for a request in the current implementation is 1. main ractor sends request to worker ractor 2. worker ractor handles response 3. worker ractor sends response to main ractor 4. main ractor writes response 5. repeat The main ractor utilizes the Async gem (specifically async-http) to handle connections concurrently, meaning each request is handled on a separate fiber. The issue I am running into is after I send a request to a worker ractor, I need to do a blocking wait until I receive a response. While I am waiting for the response, I cannot take any more connections. ### Solution If the fiber scheduler had a hook for `Ractor.receive` or `Ractor#take` (both of which are blocking), the main ractor can send the message, handle other connections while the worker processes the request. When the worker produces a message, it will then take the reqeust and write it in the socket. Specifically, I think the `block` and `unblock` hooks should be implemented for Ractors, considering Threads and Mutexes already use them. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/