From: sdwolfz via ruby-core Date: 2023-01-21T18:19:46+00:00 Subject: [ruby-core:111955] [Ruby master Feature#19326] Please add a better API for passing a Proc to a Ractor 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: ``` :271:in `new': allocator undefined for Proc (TypeError) from scripts/run.rb:9:in `run' from scripts/run.rb:14:in `
' ``` 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: ``` :820:in `make_shareable': Proc's self is not shareable: # (Ractor::IsolationError) from scripts/run.rb:5:in `initialize' from scripts/run.rb:13:in `new' from scripts/run.rb:13:in `
' ``` 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/ ______________________________________________ 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/