LoginSignup
7
1

はじめに

Rubykaigi2023にバーチャル参加をしたので、イベントレポートを書きます。
全体的に難しくてあまり理解ができていないので、sessionのレポートというよりも参加してみて初めて知った技術や印象的だったものについて概説します。

特に印象的だったのは、以下の3つです。

  • JIT
  • Ractor
  • RBS

JIT

JITとはJust In Timeの略称で、実行時コンパイラのことを指します。
僕はRubyKaigiに参加するまでは、インタプリタの内部実装を意識したことがなかったので、JITの存在すら知りませんでした。

JITコンパイラありのインタプリタがどう実行されるのかを簡単に書くと以下のようになります。

  プログラム
  
  ↓ (字句解析)

  トークン列
  
  ↓ (構文解析)

  AST

  ↓

  バイトコード(ネイティブの機械語ではない)

  ↓
  
  JITコンパイラによって実行直前にネイティブの機械語に変換される

RubyにJIT自体が導入されたのはそれほど最近のことではなく、Ruby2.6からでした。
今回は、Ruby3.2からYJITが実用段階になったということで盛り上がりを見せていました。

インタプリタがどう動いているのかを手を動かして理解するには以下の書籍がとてもよかったです。(この書籍ではJITではなく、tree-walkingで実装されている)

Ractor

RactorはRuby3.0から導入された、並列処理のための仕組みです。
Ractorが登場するまでは、マルチスレッドによる処理は並行ではあっても並列ではありませんでした。
Ractorは並列に動作することを可能にするので、複数のスレッドが同時に別の処理を行うことができます。

0 ~ 50000それぞれに対して$\sum_{k=0}^n k$を求める繰り返し処理を例に考えてみます。
(※ 動作環境は、MacBook Air Retina, 13-inch, 2020 1.1 GHz クアッドコアIntel Core i5 メモリ8GBです。)

  • 直列処理
    require 'benchmark'
    
    def calc(i)
      ans = 0
      i.downto(0) do |j|
        ans += j
      end
    end
    
    Benchmark.bm do |x|
      x.report do
        (0..50000).each{|i| calc(i)}
      end
    end

    #      user     system      total        real
    # 53.037358   0.025490  53.062848 ( 53.215683)
  • 並行処理
    Benchmark.bm do |x|
      x.report do
        arr = [
          Thread.new { (0..12500).each{|i| calc(i)}},
          Thread.new { (12501..25000).each{|i| calc(i)}},
          Thread.new { (25001..37500).each{|i| calc(i)}},
          Thread.new { (37501..50000).each{|i| calc(i)}}
        ]
        arr.each(&:value)
      end
    end
    #      user     system      total        real
    # 56.438603   0.044576  56.483179 ( 56.575608)
  • Ractorを用いた並列処理
    Benchmark.bm do |x|
      x.report do
        arr = [
          Ractor.new { (0..12500).each{|i| calc(i)}},
          Ractor.new { (12501..25000).each{|i| calc(i)}},
          Ractor.new { (25001..37500).each{|i| calc(i)}},
          Ractor.new { (37501..50000).each{|i| calc(i)}}
        ]
        arr.each(&:take)
      end
    end

    #     user     system      total        real
    # 62.608054   0.042683  62.650737 ( 26.823120)

Ractorを使った並列処理の例がかなり早いことがわかります。

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

ただ、実行時に上記のような文章が出るように、Ractorはまだまだ改善段階のようです。

RBS

RBSは、Rubyの型について記述するための言語です。
Rubyの型付けは動的であるため型注釈をすることはありませんが、このRBSを使うことによって静的に型をつけることができます。

lib/sample.rb
  class Person
    attr_reader :first_name, :last_name, :age
    
    def initialize(first_name:, last_name:, age:)
      @first_name = first_name
      @last_name = last_name
      @age = age
    end
    
    def full_name
      first_name + last_name
    end
  end

上記のようなコードの場合、以下のように型注釈をすることができます。

sig/sample.rbs
  class Person
    attr_reader first_name: String
    attr_reader last_name: String
    attr_reader age: Integer
    def initialize: (first_name: String, last_name: String, age: Integer) -> void
    def full_name: -> String
  end

で、Rubyプログラムの型情報を書いただけではそんなに嬉しくないので、その型情報から型安全かをチェックします。
これはまた別のsteepというgemが必要になります。

gemをインストールし、steep initをするとSteepfileが生成されます。
そこに以下のように記述するとlibディレクトリのRubyプログラムsigディレクトリのrbsファイルの型注釈に基づいてパースします。

  target :lib do
    check "lib"
    signature "sig"
  end
  $ steep check

現状のrbsファイルは正しく記述されているため、No type error detected. 🫖が出力されるはずです。

lib/sample.rb
  # ...
  p = Person.new(first_name: "hello", last_name: "world", age: "1")

上記を追加し、再度steep checkをすると以下のようなエラーが出力されます。

  [error] Cannot pass a value of type `::String` as an argument of type `::Integer`
  │   ::String <: ::Integer
  │     ::Object <: ::Integer
  │       ::BasicObject <: ::Integer
  │
  │ Diagnostic ID: Ruby::ArgumentTypeMismatch
  │
  └ Person.new(first_name: "hello", last_name: "world", age: "1")

ageが型注釈のIntegerと異なっているため、弾かれていることがわかります。

終わりに

RubyKaigiのようなイベントに参加したのは初めてだったので、すごく刺激的でした。
内容はとても難しかったですが、Rubyの知見を深めるたくさんのきっかけを得ることができたと思っています。
予習をしていたらもっと楽しめたなという後悔があるので、来年は予習をして臨みたいです。

来年は沖縄で開催されるので、現地に行きたい!!

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1