ラケットについて学び、ミニサイドキーを構築する


この記事では、あなたはractorについての詳細を学びますし、どのようにあなた自身のクローンを構築するためにそれらを使用することができますsidekiq ( Rubyの背景処理フレームワーク).

何がレーサーですか?
Ruby 3.0ではRactor クラス.これはRubyの俳優の同時抽象化であり、その目的はスレッド安全性の問題なしにRubyの並列実行機能を提供することである.
によるとwikipedia :

The actor model in computer science is a mathematical model of concurrent computation that treats actor as the universal primitive of concurrent computation.


俳優はできます.
  • より多くの俳優
  • メッセージを受け取る
  • メッセージを送る
  • 地元の決定をする
  • Ractor実装がまだ安定していないことに注意してください.あなたがまだ生産でそれをまだ使用しないと確信する必要があるならば、あなたがそれらを使うとき、表示される警告を見てください:

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



    レーサーの作成
    レーサーを作成するのと同じくらい簡単ですRactor.new :
    ractor = Ractor.new { puts 'Hello Ractor!' }
    

    メッセージを受け取る
    メッセージを受け取るには2つの方法があります.
    用途Ractor.receive 誰がメッセージを送っているか知りません
    message = Ractor.receive
    
    使用Ractor#take あなたがメッセージを送っているレーサーに関する参照をするならば、
    message = ractor.take
    
    これらのメソッド呼び出しがメッセージを受信するまでブロックしているので、1つを送信することはありません、またはあなたのプログラムは永遠に立ち往生される予定です.
    また、ご了承くださいobjects you are sending must be shareable .

    メッセージの送信
    あなたの受取人を知っているならば
    ractor.send(message)
    # or
    ractor << message # `<<` is an alias to `send`
    
    そうしないと
    Ractor.yield(message)
    
    Ractor.yield いくつかのレーサーまであなたのメッセージを受信するまでもブロックされます.

    地方判断
    あなたが与えられたブロックの中で何かをすることができますRactor.new . 共有オブジェクトにアクセスしない限り.ブロックの外部で定義された変数を使用しようとすると例外が送出されます.いくつかのractors間の変数を共有するには、例えばRactor::TVar gem .
    あとで使う面白い方法はRactor.select(*actors) メソッド.これは、入力としていくつかのラケットを受け取り、何かを送信する最初のレーサーを返します.
    slow_ractor = Ractor.new { sleep 2; Ractor.yield(:too_late) }
    fast_ractor = Ractor.new { Ractor.yield(:fast) }
    ractor, output = Ractor.select(slow_ractor, fast_ractor)
    # output == :fast && ractor == fast_ractor
    

    ミニsidekiqを造ろう!
    この粗いPOCは、ジョブの並列実行を達成するために、10個のラケットのプールを使用できるだけであることに注意してください.これは、エラーフロー制御、統計、キュー、およびSideKiq超便利なプロジェクトを作るすべての他の機能を処理しません.
    シンプルなデザインを構築します.
  • エーWorkerPool , 我々のプールの世話をすること
  • エーJob 基本クラスは、すべての私たちの専用ジョブから継承されます.
  • 目標は、すべてのプールロジックを処理することなく、簡単に自分の仕事を実装する人々を許可することです.

    ワークプール
    class WorkerPool
      attr_reader :ractors
    
      def initialize
        @ractors = 10.times.map { spawn_worker }
      end
    
      def spawn_worker
        Ractor.new do
          Ractor.yield(:ready)
          loop { Ractor.yield Job.run(Ractor.receive) }
        end
      end
    
      def self.run(parameters)
        ractor, _ignored_result =
          Ractor.select(*(@instance ||= new).ractors)
        ractor << parameters
      end
    end
    
    ここにトリックがあります.使用する場合Ractor.yield(:ready) , 我々は、プールのライバルが最初の何かを送信する必要があることを確認しているRactor.select 仕事をするのを忘れないでください.

    ジョブベースクラス
    class Job
      def self.process(*args)
        WorkerPool.run({ class: self, args: args })
      end
    
      def self.run(hash)
        case hash
          in { class: klass, args: args }
          klass.new.process(*args)
        end
      end
    end
    
    引数として提供するものは、共有可能でなければなりません.

    特定のジョブの実装
    何かを表示する非同期ジョブを作成したいとしましょう.
    class PrintJob < Job
      def process(message)
        puts message
      end
    end
    
    非同期で使用すると、以下のようになります.
    PrintJob.process('Hello World!')
    

    結論
    RactorはRubyでの並列実行のための新しい興味深いモデルを紹介します.
    もしあなたが人種差別の話題を面白いと思ったら、これらの興味深いリソースをチェックしてみてください.
  • https://github.com/ruby/ruby/blob/master/doc/ractor.md
  • https://docs.ruby-lang.org/en/3.0.0/Ractor.html
  • そして、あなたがこのポストが好きならば、我々をチェックしてくださいawesome weekly tech newsletter . 我々は定期的にトップルビー&JavaScriptのコンテンツを共有している!
    写真でMark Thompson