[RUBY] I tried to be able to pass multiple objects with Ractor

Conclusion

I tried to make the following code work with Ractor.

r = Ractor.new do
    v1, v2 = Ractor.recv
    puts v1
    puts v2
    puts v1.class
    puts v2.class
end

r.send(1, 2)

r.take
# => 1
# => 2
# => Integer
# => Integer

What is Ractor?

It is a mechanism to provide parallel / parallel functions introduced in Ruby3. Originally named Guild, it has been discussed for several years.

For more details, please refer to the video below.

[JA] Ractor report / Koichi Sasada @ko1

Pass the object to Ractor

You can pass an object to Ractor using the send method.

r = Ractor.new do
    v = Ractor.recv
    puts v
    puts v.class
end

r.send(1)

r.take
# => 1
# => Integer

However, you cannot pass multiple objects as shown below.

r = Ractor.new do
    v1, v2 = Ractor.recv
    puts v1
    puts v2
    puts v1.class
    puts v2.class
end

r.send(1, 2)

r.take
# =>wrong number of arguments (given 2, expected 1) (ArgumentError)

However, it seems OK to pass it as an array.

r = Ractor.new do
    v1, v2 = Ractor.recv
    puts v1
    puts v2
    puts v1.class
    puts v2.class
end

r.send([1, 2])

r.take
# => 1
# => 2
# => Integer
# => Integer

Looking at the implementation, it looks like this (in ractor.rb in the CRuby source code) The current send method takes only one object as an argument. You can also specify whether or not to move with the keyword argument move.

  def send obj, move: false
    __builtin_cexpr! %q{
      ractor_send(ec, RACTOR_PTR(self), obj, move)
    }
  end

The C function is called with __builtin_cexpr!, and the argument received by the method is passed to the C function as it is. As an aside, recent CRuby allows you to write code that passes Ruby variables to C functions as an internal implementation.

What i did

I rewrote Ractor's send method as follows.

  def send obj, *arg, move: false
    obj = arg.unshift obj unless arg.empty?
    __builtin_cexpr! %q{
      ractor_send(ec, RACTOR_PTR(self), obj, move)
    }
  end

First, the send method always takes one object as an argument. The arguments are rewritten like ʻobj, * arg, move: falseto maintain that behavior. Also, if multiple objects are passed, such assend (1, 2), the arguments are passed as an array to * arg`.

If ʻarg is not an empty array, then multiple objects are being passed, and the ʻobj that is finally passed to the C function is converted to a merge of the first argument and the variadic argument. I will.

All you have to do is build the modified CRuby source code.

You can now pass multiple objects to Ractor as follows:

r = Ractor.new do
    v1, v2 = Ractor.recv
    puts v1
    puts v2
    puts v1.class
    puts v2.class
end

r.send(1, 2)

r.take
# => 1
# => 2
# => Integer
# => Integer

reference

ref: Guild → Ractor ref: https://github.com/ko1/ruby/blob/ractor/ractor.ja.md ref: [[JA Ractor report / Koichi Sasada @ko1

Postscript

By the way, if you want a monkey patch, you can create a method wrapped as follows.

class Ractor
    def multi_send(obj, *args, move: true)
        obj = args.unshift obj unless args.empty?
        send(obj, move: move)
    end 
end

r = Ractor.new do
    v1, v2 = Ractor.recv
    puts v1
    puts v2
    puts v1.class
    puts v2.class
end

r.multi_send(1, 2)

r.take

The range of monkey patches is wide, so if you use them in practice, it may be better to use refinements because it has less effect.

module RefineRactor
    refine Ractor do
        def multi_send(obj, *args, move: true)
            obj = args.unshift obj unless args.empty?
            send(obj, move: move)
        end 
    end
end

using RefineRactor

r = Ractor.new do
    v1, v2 = Ractor.recv
    puts v1
    puts v2
    puts v1.class
    puts v2.class
end

r.multi_send(1, 2)

r.take

Recommended Posts

I tried to be able to pass multiple objects with Ractor
I tried to interact with Java
I tried to get started with WebAssembly
I tried to implement ModanShogi with Kinx
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried to make Basic authentication with Java
I tried to manage struts configuration with Coggle
I tried to manage login information with JMX
I tried to break a block with java (1)
I want to be able to read a file using refile with administrate [rails6]
I tried what I wanted to try with Stream softly.
I tried to implement file upload with Spring MVC
I tried to read and output CSV with Outsystems
I tried to implement TCP / IP + BIO with JAVA
[Java 11] I tried to execute Java without compiling with javac
I started MySQL 5.7 with docker-compose and tried to connect
I tried to get started with Spring Data JPA
I tried to draw animation with Blazor + canvas API
I tried to implement Stalin sort with Java Collector
roman numerals (I tried to simplify it with hash)
I tried to make an introduction to PHP + MySQL with Docker
I tried to modernize a Java EE application with OpenShift.
I tried DI with Ruby
I tried to increase the processing speed with spiritual engineering
I want to be able to pass items that have been validated with regular expressions even if they are left blank
[Rails] I tried to implement batch processing with Rake task
I tried to automate LibreOffice Calc with Ruby + PyCall.rb (Ubuntu 18.04)
I tried UPSERT with PostgreSQL.
I tried BIND with Docker
I tried to verify yum-cron
I tried to create a padrino development environment with Docker
I tried upgrading from CentOS 6.5 to CentOS 7 with the upgrade tool
I want to pass the startup command to postgres with docker-compose.
I tried to solve the problem of "multi-stage selection" with Ruby
I want to be able to think and write regular expressions myself. ..
I tried connecting to MySQL using JDBC Template with Spring MVC
I tried to implement the image preview function with Rails / jQuery
I tried to build an http2 development environment with Eclipse + Tomcat
I tried to implement flexible OR mapping with MyBatis Dynamic SQL
I tried connecting to Oracle Autonomous Database 21c with JDBC Thin
I tried to reimplement Ruby Float (arg, exception: true) with builtin
I tried to make an Android application with MVC now (Java)
I tried to check the operation of gRPC server with grpcurl
I tried to make a group function (bulletin board) with Rails
I tried to chew C # (indexer)
I tried using JOOQ with Gradle
I tried morphological analysis with MeCab
I tried to summarize iOS 14 support
To display multiple lines with UILabel
I tried UDP communication with Java
I tried to explain the method
I tried GraphQL with Spring Boot
I tried to summarize Java learning (1)
I tried to understand nil guard
I tried to summarize Java 8 now
I tried to chew C # (polymorphism: polymorphism)
I tried customizing slim with Scaffold
I tried to explain Active Hash
I tried to solve the past 10 questions that should be solved after registering with AtCoder in Java
Fixed to be able to save a specific column empty with active record
[Java] Java was said to be okay to concatenate strings with +, so I checked