programing

루비는 진짜 멀티스레딩이 있나요?

showcode 2023. 6. 14. 22:02
반응형

루비는 진짜 멀티스레딩이 있나요?

저는 녹색 실을 사용하는 루비의 "협동" 스레드에 대해 알고 있습니다.여러 CPU 코어를 처리에 사용하기 위해 애플리케이션에서 실제 "OS 레벨" 스레드를 생성하려면 어떻게 해야 합니까?

Jörg의 2011년 9월 논평으로 업데이트됨

당신은 여기서 두 가지 매우 다른 것을 혼동하고 있는 것 같습니다: 루비 프로그래밍 언어와 루비 프로그래밍 언어의 특정 구현의 특정 스레드 모델입니다.현재 루비 프로그래밍 언어에는 약 11개의 다른 구현체가 있으며, 매우 다르고 고유한 스레드 모델이 있습니다.

(불행히도 실제 운영 환경에서 사용할 수 있는 구현은 11개 중 2개에 불과하지만 연말에는 그 수가 4개 또는 5개까지 늘어날 것으로 예상됩니다.) (업데이트: MRI, JRuby, YARV(Ruby 1.9 인터프리터), Rubinius 및 IronRuby.

  1. 첫 번째 구현은 실제로 이름이 없기 때문에 참조하기가 상당히 어색하고 정말 짜증나고 혼란스럽습니다.이는 루비 프로그래밍 언어의 기능과 특정 루비 구현 사이에 끝없는 혼란을 초래하기 때문에 이름이 없는 것보다 훨씬 더 짜증나고 혼란스러운 "루비"로 가장 자주 언급됩니다.

또한 "MRI"("Matz's Ruby Implementation"의 경우), CRuby 또는 MatzRuby라고도 합니다.

MRI는 인터프리터 내에서 Ruby Threads를 Green Thread로 구현합니다.안타깝게도 이러한 스레드를 병렬로 예약할 수 없으므로 한 번에 하나의 스레드만 실행할 수 있습니다.

그러나 임의의 수의 C 스레드(POSIX 스레드 등)가 Ruby 스레드와 병렬로 실행될 수 있으므로 자체 스레드를 생성하는 외부 C 라이브러리 또는 MRI C Extensions는 여전히 병렬로 실행될 수 있습니다.

  1. 두 번째 구현은 YARV("Yet Another Ruby VM"의 줄임말)입니다. YARV는 Ruby Thread를 POSIX 또는 Windows NT 스레드로 구현하지만 GIL(Global Interpreter Lock)을 사용하여 한 번에 하나의 Ruby Thread만 예약할 수 있습니다.

MRI와 마찬가지로 C 스레드는 실제로 루비 스레드와 병렬로 실행될 수 있습니다.

미래에는, GIL이 더 미세한 잠금장치로 분해되어 더 많은 코드가 실제로 병렬로 실행될 수 있게 될 수도 있습니다. 하지만 그것은 너무 멀어서 아직 계획조차 되어 있지 않습니다.

  1. JRuby는 Ruby 스레드를 네이티브 스레드로 구현합니다. 여기서 JVM의 경우 "네이티브 스레드"는 분명히 "JVM 스레드"를 의미합니다.JRuby는 그들에게 추가적인 잠금을 하지 않습니다.따라서 이러한 스레드가 실제로 병렬로 실행될 수 있는지 여부는 JVM에 따라 달라집니다. 일부 JVM은 JVM 스레드를 OS 스레드로 구현하고 일부는 Green 스레드로 구현합니다.(Sun/Oracle의 메인스트림 JVM은 JDK 1.3 이후의 OS 스레드만을 사용합니다.)

  2. 또한 XRubyRuby 스레드를 JVM 스레드로 구현합니다.업데이트: XRuby가 종료되었습니다.

  3. IronRubyRuby Threads를 네이티브 스레드로 구현합니다. 여기서 CLR의 경우 "네이티브 스레드"는 분명히 "CLR 스레드"를 의미합니다.IronRuby는 추가 잠금을 부과하지 않으므로 CLR에서 이를 지원하는 한 병렬로 실행해야 합니다.

  4. 또한 Ruby.NETCLR 스레드로 Ruby 스레드를 구현합니다.업데이트:루비.NET이 죽었습니다.

  5. Rubinius는 가상 시스템 내에 Ruby 스레드를 녹색 스레드로 구현합니다.좀 더 정확하게 말하면, Rubinius VM은 "Task"라고 하는 매우 가볍고 유연한 동시성/병렬성/비로컬 제어 흐름 구성을 내보내고, 다른 모든 동시성 구성(이 논의의 스레드는 물론 연속성, 행위자 및 기타 요소)은 태스크를 사용하여 순수 루비로 구현됩니다.

그러나 루비니우스는 스레드를 병렬로 예약할 수 없으며, 이는 큰 문제가 아니라고 덧붙였습니다.Rubinius는 이미 하나의 Rubinius 프로세스 내에서 여러 POSIX 스레드에서 여러 VM 인스턴스를 병렬로 실행할 수 있습니다.스레드는 실제로 Ruby에서 구현되므로 다른 Ruby 개체와 마찬가지로 직렬화되어 다른 POSIX 스레드의 다른 VM으로 전송될 수 있습니다. (이 모델은 BEAM Erlang VM에서 SMP 동시성에 사용하는 모델과 동일합니다.)이미 루비니우스 액터스를 위해 구현되었습니다.)

업데이트: 이 답변에서 Rubinius에 대한 정보는 더 이상 존재하지 않는 샷건 VM에 대한 것입니다."새" C++ VM에서 여러 VM(예: Erlang/B)에 예약된 녹색 스레드를 사용하지 않습니다.EAM 스타일)에서는 CLR, Mono 및 거의 모든 JVM에서 사용하는 모델과 마찬가지로 기존의 단일 VM과 여러 기본 OS 스레드 모델을 사용합니다.

  1. MacRuby는 Objective-C 런타임 및 코어 파운데이션과 코코아 프레임워크 위에 YARV의 포트로 시작했습니다.이제 YARV에서 크게 벗어났지만, AFAIK는 현재 YARV와 동일한 스레드화 모델을 공유하고 있습니다.업데이트:MacRuby는 더 이상 사용되지 않는 것으로 선언되고 이후 버전의 MacOSX에서 제거될 사과 가비지 수집기에 의존합니다. MacRuby는 비활성 상태입니다.

  2. Cardinal은 앵무새 가상 시스템을 위한 루비 구현입니다.아직 스레드를 구현하지는 않지만 구현할 때는 패럿 스레드로 구현할 것입니다.업데이트: 카디널은 매우 활동적이지 않거나 사망한 것 같습니다.

  3. MagLevGemStone/S Smalltalk VM용 Ruby 구현입니다.GemStone/S가 어떤 스레드 모델을 사용하는지, MagLev가 어떤 스레드 모델을 사용하는지, 스레드가 아직 구현되지 않았더라도(아마도) 아무런 정보가 없습니다.

  4. HotRuby자체적으로 완전한 Ruby 구현이 아닙니다.JavaScript에서 YARV 바이트코드 VM을 구현한 것입니다.HotRuby는 스레드를 지원하지 않습니다(아직 지원하지 않음). 지원할 경우 자바스크립트가 진정한 병렬화를 지원하지 않기 때문에 병렬로 실행할 수 없습니다.그러나 HotRuby에는 ActionScript 버전이 있으며 ActionScript는 실제로 병렬 처리를 지원할 수 있습니다.업데이트:핫 루비가 죽었어요

불행하게도, 이 11개의 Ruby 구현 중 실제로 프로덕션 준비가 된 것은 MRI와 JRuby 두 가지뿐입니다.

따라서 진정한 병렬 스레드를 원한다면 현재 JRuby가 유일한 선택입니다. 나쁜 선택은 아닙니다. JRuby는 MRI보다 속도가 빠르고 안정적입니다.

그렇지 않으면, "클래식" Ruby 솔루션은 병렬 처리를 위해 스레드 대신 프로세스를 사용하는 것입니다.Ruby Core Library에는 다른 Ruby 프로세스를 쉽게 분기할 수 있는 방법이 포함된 모듈이 있습니다.또한 Ruby Standard Library에는 Distributed Ruby(dRuby / dRb) 라이브러리가 포함되어 있어 Ruby 코드가 동일한 시스템뿐만 아니라 네트워크 전체에 걸쳐 여러 프로세스에 걸쳐 사소한 분산이 가능합니다.

Ruby 1.8에는 녹색 스레드만 있으며, 실제 "OS 수준" 스레드를 만들 수 없습니다.그러나 루비 1.9에는 실제 OS 수준 스레드를 만들 수 있는 파이버라는 새로운 기능이 포함될 것입니다.불행하게도, 루비 1.9는 아직 베타 단계에 있으며, 몇 달 안에 안정적으로 운영될 예정입니다.

또 다른 대안은 JRuby를 사용하는 것입니다.JRuby는 스레드를 OS 수준의 광고로 구현하며, "녹색 스레드"가 없습니다.JRuby의 최신 버전은 1.1.4이며 Ruby 1.8에 해당합니다.

: 구에따다릅니다라현다.

  • MRI는 없고, YARV가 더 가깝습니다.
  • JRUby와 MacRuby가 가지고 있습니다.




루비는 다음과 같은 폐쇄를 가지고 있습니다.Blocks,lambdas그리고.ProcsJRuby의 폐쇄와 다중 코어를 최대한 활용하기 위해 Java의 실행자는 유용합니다. MacRuby의 경우 GCD의 대기열을 좋아합니다.

실제 "OS 레벨" 스레드를 생성할 수 있다고 해서 병렬 처리에 여러 CPU 코어를 사용할 수 있는 것은 아닙니다.아래의 예를 보십시오.

다음은 Ruby 2.1.0을 사용하여 3개의 스레드를 사용하는 간단한 Ruby 프로그램의 출력입니다.

(jalcazar@mac ~)$ ps -M 69877
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 69877 s002    0.0 S    31T   0:00.01   0:00.04 /Users/jalcazar/.rvm/rubies/ruby-2.1.0/bin/ruby threads.rb
   69877         0.0 S    31T   0:00.01   0:00.00 
   69877        33.4 S    31T   0:00.01   0:08.73 
   69877        43.1 S    31T   0:00.01   0:08.73 
   69877        22.8 R    31T   0:00.01   0:08.65 

와 같이 OS 상태가 만 있습니다.R실행 중입니다.이는 Ruby의 스레드 구현 방식에 제한이 있기 때문입니다.



지금은 JR유비와 같은 프로그램입니다. 개의 됩니다.R그 말은 그들이 평행으로 달리고 있다는 것을 의미합니다.

(jalcazar@mac ~)$ ps -M 72286
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 72286 s002    0.0 S    31T   0:00.01   0:00.01 /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/bin/java -Djdk.home= -Djruby.home=/Users/jalcazar/.rvm/rubies/jruby-1.7.10 -Djruby.script=jruby -Djruby.shell=/bin/sh -Djffi.boot.library.path=/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jni:/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jni/Darwin -Xss2048k -Dsun.java.command=org.jruby.Main -cp  -Xbootclasspath/a:/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jruby.jar -Xmx1924M -XX:PermSize=992m -Dfile.encoding=UTF-8 org/jruby/Main threads.rb
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    33T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.09   0:02.34 
   72286         7.9 S    31T   0:00.15   0:04.63 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.04   0:01.68 
   72286         0.0 S    31T   0:00.03   0:01.54 
   72286         0.0 S    31T   0:00.00   0:00.00 
   72286         0.0 S    31T   0:00.01   0:00.01 
   72286         0.0 S    31T   0:00.00   0:00.01 
   72286         0.0 S    31T   0:00.00   0:00.03 
   72286        74.2 R    31T   0:09.21   0:37.73 
   72286        72.4 R    31T   0:09.24   0:37.71 
   72286        74.7 R    31T   0:09.24   0:37.80 


지금은 맥루비와 같은 프로그램입니다.또한 3개의 스레드가 병렬로 실행됩니다.이는 MacRuby 스레드가 POSIX 스레드(실제 "OS 레벨" 스레드)이며 GVL이 없기 때문입니다.

(jalcazar@mac ~)$ ps -M 38293
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 38293 s002    0.0 R     0T   0:00.02   0:00.10 /Users/jalcazar/.rvm/rubies/macruby-0.12/usr/bin/macruby threads.rb
   38293         0.0 S    33T   0:00.00   0:00.00 
   38293       100.0 R    31T   0:00.04   0:21.92 
   38293       100.0 R    31T   0:00.04   0:21.95 
   38293       100.0 R    31T   0:00.04   0:21.99 


다시 한 번, 같은 프로그램이지만 지금은 예전의 MRI를 사용합니다.은 그린됩니다.

(jalcazar@mac ~)$ ps -M 70032
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 70032 s002  100.0 R    31T   0:00.08   0:26.62 /Users/jalcazar/.rvm/rubies/ruby-1.8.7-p374/bin/ruby threads.rb



루비 멀티 스레드에 관심이 있다면 포크 핸들러사용한 병렬 프로그램 디버깅 보고서가 흥미로울 수 있습니다.
루비 내부에 대한 더 일반적인 개요는 루비 현미경 아래에서 읽는 것이 좋습니다.
또한, 루비 스레드와 C in Omniref의 Global Interpreter Lock은 소스 코드에서 루비 스레드가 병렬로 실행되지 않는 이유를 설명합니다.

drb를 사용하는 것은 어떻습니까?실제 멀티 스레드가 아니라 여러 프로세스 간의 통신이지만 1.8로 사용할 수 있으며 마찰력이 상당히 낮습니다.

"시스템 모니터"가 이 질문에 답하도록 하겠습니다.i7(4 하이퍼스레딩 코어) 기계에서 실행되는 8개의 Ruby 스레드로 동일한 코드(아래 소수 계산)를 실행하고 있습니다.첫 번째 실행은 다음과 같습니다.

jruby 1.5.6(ruby 1.8.7 패치 수준 249)(2014-02-036586)(OpenJDK 64비트 서버 VM 1.7.0_75) [amd64-java]

두 번째는 다음과 같습니다.

ruby 2.1.2p95 (2014-05-08) [x86_64-linux-linux-linux]

흥미롭게도, CPU는 JRuby 스레드의 경우 더 높지만, 해석된 Ruby의 경우 완료 시간이 약간 더 짧습니다.그래프로 보면 알 수 없지만, 두 번째(Ruby 해석) 실행은 CPU의 1/2 정도를 사용합니다(하이퍼스레딩 없음).

enter image description here

def eratosthenes(n)
  nums = [nil, nil, *2..n]
  (2..Math.sqrt(n)).each do |i|
    (i**2..n).step(i){|m| nums[m] = nil}  if nums[i]
  end
  nums.compact
end

MAX_PRIME=10000000
THREADS=8
threads = []

1.upto(THREADS) do |num|
  puts "Starting thread #{num}"
  threads[num]=Thread.new { eratosthenes MAX_PRIME }
end

1.upto(THREADS) do |num|
    threads[num].join
end

MRI를 사용하는 경우 확장으로 또는 루비 인라인 보석을 사용하여 C에 스레드 코드를 작성할 수 있습니다.

Ruby for Production 레벨 시스템(베타를 사용할 수 없는 시스템)에서 병렬화가 정말 필요하다면 프로세스가 더 나은 대안이 될 수 있습니다.
하지만 우선 JRuby 아래에서 스레드를 시도해 볼 가치가 있습니다.

또한 Ruby 아래에서 스레드화의 미래에 관심이 있다면 이 기사가 유용할 수 있습니다.

여기 린다의 루비 구현인 린다에 대한 몇 가지 정보가 있습니다. http://charmalloc.blogspot.com/2009/12/linda-tuples-rinda-drb-parallel.html

해당 답변을 편집할 수 없으므로 여기에 새 답변을 추가하십시오.

업데이트(2017-05-08)

이 문서는 매우 오래되었으며 정보가 현재(2017) 트레드를 따르지 않습니다. 다음은 몇 가지 보충 자료입니다.

  1. Opal은 Ruby to JavaScript 소스 간 컴파일러입니다.또한 Ruby corelib을 구현하고 있으며, 현재 매우 활발한 개발 작업을 수행하고 있으며, 많은 (프론트엔드) 프레임워크가 존재하고 있으며, 프로덕션 준비가 되어 있습니다.자바스크립트 기반이기 때문에 병렬 스레드를 지원하지 않습니다.

  2. Truffleruby는 Ruby 프로그래밍 언어의 고성능 구현입니다.Oracle Labs가 GraalVM을 기반으로 구축한 TruffleRuby는 JRuby의 포크로, 루비니우스 프로젝트의 코드와 결합하고 Ruby의 표준 구현에서 가져온 코드, MRI, 아직 실시간 개발, 프로덕션 준비가 되지 않았습니다.이 버전의 루비는 성능을 위해 탄생한 것 같습니다. 병렬 스레드를 지원하는지는 모르겠지만, 그래야 한다고 생각합니다.

언급URL : https://stackoverflow.com/questions/56087/does-ruby-have-real-multithreading

반응형