Issue #19326 has been updated by sdwolfz (Codruț Gușoi).
I thought Ractor.new would only accept literal
blocks.
I hope not, passing an arbitrary block helps with building functionality on top of Ractors
(that I want to do).
The problem is the usual "does not respect the
intent of the writer of the block, which expected a specific self".
My "Worker" class will have documentation stating that self is replaced and all
dependencies need to be passed through the constructor so that's not going to be an
issue.
Also it only works if you are fine to create a Ractor
per block, which seems a big overhead.
I could have a "Ractor pool" basically limiting the number of Ractors that can
run at the same time. Still, the overhead could be improved with future Ruby releases
(just like it is for Erlang/Elixir). For all practical purposes so far the overhead is
negligible compared to the work done in the blocks.
Maybe Proc#isolate(new_self) or so should be exposed.
This would be a nice functionality to have, indeed.
OTOH Ractor is incompatible with most gems out there,
so seems of limited usefulness.
It will become better when Ractor is stabilised, right now I have all I need working.
For true parallelism compatible with existing Ruby
code, use threads on TruffleRuby/JRuby.
I'd rather use the real Ruby and stay away from Oracle.
All that being said, I'm really interested to see how this functionality evolves.
----------------------------------------
Feature #19326: Please add a better API for passing a Proc to a Ractor
https://bugs.ruby-lang.org/issues/19326#change-101390
* Author: sdwolfz (Codruț Gușoi)
* Status: Open
* Priority: Normal
----------------------------------------
Example 1:
```ruby
class Worker
def initialize(&block)
@block = block
end
def run
Ractor.new(@block, &:call)
end
end
worker = Worker.new { 1 }
puts worker.run.take
```
Errors with:
```
<internal:ractor>:271:in `new': allocator undefined for Proc (TypeError)
from scripts/run.rb:9:in `run'
from scripts/run.rb:14:in `<main>'
```
Example 2:
```ruby
class Worker
def initialize(&block)
@block = Ractor.make_shareable(block)
end
def run
Ractor.new(@block, &:call)
end
end
worker = Worker.new { 1 }
puts worker.run.take
```
Errors with:
```
<internal:ractor>:820:in `make_shareable': Proc's self is not shareable:
#<Proc:0x00007f00394c38b8 scripts/run.rb:13> (Ractor::IsolationError)
from scripts/run.rb:5:in `initialize'
from scripts/run.rb:13:in `new'
from scripts/run.rb:13:in `<main>'
```
Example 3:
```ruby
class Worker
def initialize(&block)
@block = Ractor.make_shareable(block)
end
def run
Ractor.new(@block, &:call)
end
end
worker = Ractor.current.instance_eval { Worker.new { 1 } }
puts worker.run.take
```
Works, but having `Ractor.current.instance_eval` as a wrapper around the block is not
ideal, as Ractor is supposed to be only an implementation detail in Worker.
I know about
https://bugs.ruby-lang.org/issues/18243 and the discussion around
`proc.bind(nil)`. That would actually be ideal, as for the purposes if why I want this
functionality I don't care what `self` is in a block, and the less it has access to
the better.
The general idea of Worker is to have a Ractor be able to lazily execute an arbitrary
proc. And all the bindings it would need would be passed explicitly, either through `args`
in the constructor or through `send`/`receive`, so `self` would really not matter.
The benefit: this would make it so concurrent code can be more easily be implemented with
Ractors as currently you can execute an arbitrary proc by passing it to a Thread (but you
don't get the nice data isolation).
--
https://bugs.ruby-lang.org/