Rectors에 대해 알아보고 미니 사이드키크를 구축하세요.

10648 단어 programmingruby
이 기사에서는 Ractor에 대해 자세히 알아보고 이를 사용하여 sidekiq(Ruby용 백그라운드 처리 프레임워크)의 복제본을 빌드하는 방법에 대해 알아봅니다.

랙터란?



Ruby 3.0은 Ractor 클래스를 도입했습니다. 이것은 Ruby의 Actor와 같은 동시 추상화이며, 그 목표는 스레드 안전성 문제 없이 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.



액터는 다음을 수행할 수 있습니다.
  • 더 많은 액터 생성
  • 메시지 수신
  • 메시지 보내기
  • 지역 결정을 내리십시오

  • Rector 구현은 아직 안정적이지 않으므로 프로덕션 코드에 사용하지 마십시오. 프로덕션에서 (아직) 사용하지 않도록 확신해야 하는 경우 사용할 때 표시되는 경고를 참조하세요.

    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!' }
    


    메시지 수신



    메시지를 보내는 랙터에 대한 참조가 있는지 여부에 따라 메시지를 수신하는 두 가지 방법이 있습니다.

    메시지를 보내는 사람을 모르는 경우 Ractor.receive를 사용합니다.

    message = Ractor.receive
    


    메시지를 보내는 랙터에 대한 참조가 있으면 Ractor#take를 사용하십시오.

    message = ractor.take
    


    이러한 메소드 호출은 메시지를 수신할 때까지 차단되므로 절대 보내지 않을 랙터로부터 메시지를 기대하지 마십시오. 그렇지 않으면 프로그램이 영원히 중단될 것입니다.

    또한 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 에 주어진 블록에서 원하는 모든 것을 할 수 있습니다. 공유 개체에 액세스하지 않는 한. 블록 외부에 정의된 변수를 사용하려고 하면 예외가 발생합니다. 여러 랙터 간에 변수를 공유하려면 예를 들어 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
    


    미니 사이드키크를 만들어보자!



    이 조잡한 POC를 사용하면 작업의 병렬 실행을 달성하기 위해 10개의 랙터 풀만 사용할 수 있습니다. 오류 흐름 제어, 통계, 대기열 및 sidekiq를 매우 유용한 프로젝트로 만드는 기타 모든 기능을 처리하지 않습니다.

    우리는 다음을 사용하여 간단한 디자인을 만들 것입니다.
  • A 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 을 확인하십시오. 우리는 정기적으로 최고의 루비 및 자바스크립트 콘텐츠를 공유하고 있습니다!

    사진Mark Thompson

    좋은 웹페이지 즐겨찾기