window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster가 이미 존재합니다') } else { w.LeadBooster = { q: [], on: 함수 (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: 함수 (n) { this.q.push({ t: 't', n: n }) }, } } })() 루비 포크 및 스레딩 - The Codest
The Codest
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 산업 분야
    • 핀테크 및 뱅킹
    • E-commerce
    • 애드테크
    • 헬스 테크
    • 제조
    • 물류
    • 자동차
    • IOT
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
뒤로 화살표 뒤로 가기
2016-10-06
소프트웨어 개발

루비에서 포크 및 스레딩

마렉 기를라흐

아시다시피 루비에는 MRI, JRuby, Rubinius, Opal, RubyMotion 등과 같은 몇 가지 구현이 있으며 각 구현은 서로 다른 코드 실행 패턴을 사용할 수 있습니다. 이 문서에서는 이 중 처음 세 가지에 초점을 맞추고 MRI를 비교합니다.

아시다시피 루비에는 MRI, JRuby, Rubinius, Opal, RubyMotion 등과 같은 몇 가지 구현이 있으며, 각각 다른 패턴을 사용할 수 있습니다. 코드 실행을 살펴봅니다. 이 글에서는 이 중 처음 세 가지에 초점을 맞추고 CPU 집약적인 알고리즘 처리, 파일 복사 등 다양한 상황에서 포크 및 스레딩의 적합성을 평가하는 몇 가지 샘플 스크립트를 실행하여 MRI(현재 가장 많이 사용되는 구현)를 JRuby 및 Rubinius와 비교합니다."실습을 통한 학습"을 시작하기 전에 몇 가지 기본 용어를 수정해야 합니다.

포크

  • 는 새 자식 프로세스(부모 프로세스의 복사본)입니다.
  • 새 프로세스 식별자(PID)가 있습니다.
  • 별도의 메모리가 있습니다.*
  • 는 메시지 큐, 파일, 소켓 등과 같은 프로세스 간 통신(IPC) 채널을 통해 다른 프로세스와 통신합니다.
  • 부모 프로세스가 종료되더라도 존재합니다.
  • 는 POSIX 호출로 주로 유닉스 플랫폼에서 작동합니다.

스레드

  • 는 프로세스 내에서 작동하는 "단지" 실행 컨텍스트입니다.
  • 모든 메모리를 다른 사용자와 공유합니다(기본적으로 포크보다 적은 메모리를 사용합니다).
  • 공유 메모리 객체를 통해 다른 사람과 통신합니다.
  • 프로세스와 함께 죽습니다.
  • 는 굶주림, 교착 상태 등과 같은 일반적인 멀티 스레딩 문제를 일으킵니다.

포크와 스레드를 사용하는 많은 도구가 있으며, 애플리케이션 서버 수준에서는 Unicorn(포크) 및 Puma(스레드), 백그라운드 작업 수준에서는 Resque(포크) 및 Sidekiq(스레드) 등이 일상적으로 사용되고 있습니다.

다음 표는 주요 루비 구현에서 포크 및 스레딩에 대한 지원을 보여줍니다.

루비 구현포크스레딩
MRI예예(GIL**에 의해 제한됨)
JRuby–예
루비니우스예예

이 주제에서는 병렬성과 동시성이라는 두 가지 마법의 단어가 부메랑처럼 돌아오고 있으므로 이에 대해 조금 더 설명할 필요가 있습니다. 우선, 이 두 용어는 같은 의미로 사용할 수 없습니다. 간단히 말해 병렬성은 두 개 이상의 작업이 정확히 동시에 처리되는 경우에 대해 이야기할 수 있습니다. 동시성은 두 개 이상의 작업이 겹치는 시간대에 처리될 때 발생합니다(반드시 동시에 처리될 필요는 없음). 예, 광범위한 설명이지만 차이점을 알아차리고 이 글의 나머지 부분을 이해하는 데 도움이 되기에 충분합니다.

2020년 프론트엔드 보고서

다음 표에는 병렬 처리 및 동시성 지원이 나와 있습니다.

루비 구현병렬 처리(포크를 통한)병렬 처리(스레드를 통한)동시성
MRI예아니요예
JRuby–예예
루비니우스예예(버전 2.X부터)예

이론은 여기까지입니다 - 실제로 확인해 보겠습니다!

  • 별도의 메모리를 사용한다고 해서 부모 프로세스와 동일한 양의 메모리를 사용할 필요는 없습니다. 몇 가지 메모리 최적화 기술이 있습니다. 그 중 하나는 부모 프로세스가 할당된 메모리를 복사하지 않고 자식 프로세스와 공유할 수 있도록 하는 CoW(Copy on Write)입니다. CoW를 사용하면 자식 프로세스가 공유 메모리를 수정하는 경우에만 추가 메모리가 필요합니다. 루비에서는 모든 구현이 CoW 친화적인 것은 아닙니다. 예를 들어 MRI에서는 버전 2.X부터 이를 완벽하게 지원합니다. 이 버전 이전에는 각 포크가 부모 프로세스만큼 많은 메모리를 소비했습니다.
  • MRI의 가장 큰 장점/단점 중 하나(부적절한 대안은 제외)는 GIL(글로벌 인터프리터 잠금)을 사용한다는 점입니다. 간단히 말해, 이 메커니즘은 스레드 실행을 동기화하기 때문에 한 번에 하나의 스레드만 실행할 수 있습니다. 하지만 잠깐만요... MRI에서 스레드를 사용할 필요가 전혀 없다는 뜻일까요? 그 답은 GIL 내부를 이해하거나 적어도 이 글의 코드 샘플을 살펴보면 알 수 있습니다.

테스트 사례

루비의 구현에서 포크와 스레딩이 어떻게 작동하는지 보여주기 위해 다음과 같은 간단한 클래스를 만들었습니다. 테스트 를 상속하는 몇 가지 클래스가 있습니다. 각 클래스에는 처리할 작업이 다릅니다. 기본적으로 모든 작업은 루프에서 네 번 실행됩니다. 또한 모든 작업은 순차, 포크, 스레드의 세 가지 코드 실행 유형에 대해 실행됩니다. 또한, Benchmark.bmbm 는 코드 블록을 두 번 실행합니다. 첫 번째는 런타임 환경을 설정하고 실행하기 위해, 두 번째는 측정하기 위해 실행합니다. 이 문서에 제시된 모든 결과는 두 번째 실행에서 얻은 것입니다. 물론, 심지어 bmbm 메서드가 완벽한 격리를 보장하지는 않지만 여러 코드 실행 간의 차이는 미미합니다.

"벤치마크" 필요

클래스 Test
  AMOUNT = 4

  def run
    Benchmark.bmbm do |b|
      b.report("sequential") { sequential }
      b.report("포킹") { 포킹 }
      b.report("스레딩") { 스레딩 }
    end
  end

  private

  def sequential
    AMOUNT.times { 수행 }
  end

  def 포크
    AMOUNT.times do
      포크 do
        perform
      end
    end

    Process.waitall
  구조 NotImplementedError => e
    # 포크 메서드는 JRuby에서 사용할 수 없습니다.
    넣어
  end

  def 스레딩
    threads = []

    AMOUNT.times do
      threads << Thread.new do
        perform
      end
    end

    threads.map(&:join)
  end

  def perform
    raise "구현되지 않음"
  end
end
부하 테스트

계산을 루프에서 실행하여 큰 CPU 부하를 생성합니다.

LoadTest 클래스 < Test
  def perform
    1000.times { 1000.times { 2**3**4 } }
  end
end

실행해 보겠습니다...

LoadTest.new.run

...그리고 결과 확인

MRIJRuby루비니우스
순차적1.8629282.0890001.918873
포크0.945018–1.178322
스레딩1.9139821.1070001.213315

보시다시피 순차적으로 실행한 결과는 비슷합니다. 물론 솔루션 간에 약간의 차이가 있지만 이는 다양한 인터프리터에서 선택한 방법을 기본적으로 구현하기 때문에 발생하는 문제입니다.

이 예제에서 포크는 상당한 성능 향상(코드가 거의 두 배 빠르게 실행됨)을 가져옵니다.

스레딩은 포크와 비슷한 결과를 제공하지만 JRuby와 Rubinius에만 해당됩니다. MRI에서 스레드를 사용하여 샘플을 실행하면 순차적 방법보다 시간이 조금 더 걸립니다. 적어도 두 가지 이유가 있습니다. 첫째, GIL은 스레드를 순차적으로 실행하도록 강제하므로 완벽한 세계에서는 실행 시간이 순차 실행과 동일해야 하지만, GIL 작업(스레드 간 전환 등)에 대한 시간 손실도 발생합니다. 둘째, 스레드를 생성하는 데 약간의 오버헤드 시간도 필요합니다.

이 예는 MRI에서 사용 스레드의 의미에 대한 질문에 대한 답을 제공하지 않습니다. 다른 예시를 살펴봅시다.

스누즈 테스트

절전 모드를 실행합니다.

클래스 SnoozeTest < Test
  def perform
    sleep 1
  end
end

결과는 다음과 같습니다.

MRIJRuby루비니우스
순차적4.0046204.0060004.003186
포크1.022066–1.028381
스레딩1.0015481.0040001.003642

보시다시피, 각 구현은 순차 및 포크 실행뿐만 아니라 스레딩 실행에서도 비슷한 결과를 제공합니다. 그렇다면 왜 MRI가 JRuby 및 Rubinius와 동일한 성능 향상을 가져올까요? 그 답은 다음과 같은 구현에 있습니다. 수면.

MRI 수면 메서드는 다음과 같이 구현됩니다. rb_thread_wait_for 라는 다른 함수를 사용하는 native_sleep. 구현을 간단히 살펴 보겠습니다 (코드는 단순화되었으며 원래 구현은 다음에서 찾을 수 있습니다. 여기):

정적 void
native_sleep(rb_thread_t *th, 구조체 timeval *timeout_tv)
{
  ...

  GVL_UNLOCK_BEGIN();
  {
    // 여기서 몇 가지 작업을 수행합니다.
  }
  gvl_unlock_end();

  thread_debug("native_sleep donen");
 }

이 함수가 중요한 이유는 엄격한 루비 컨텍스트를 사용하는 것 외에도 일부 작업을 수행하기 위해 시스템 컨텍스트로 전환하기 때문입니다. 이런 상황에서는 루비 프로세스가 할 일이 없습니다... 시간 낭비의 좋은 예시인가요? 아니요, GIL에 이런 말이 있습니다: "이 스레드에서 할 일이 없나요? 다른 스레드로 전환하고 잠시 후에 다시 돌아오자"라는 말이 있기 때문입니다. 이 작업은 다음을 사용하여 GIL을 잠금 해제하고 잠그면 가능합니다. gvl_unlock_begin() 그리고 gvl_unlock_end() 함수.

상황은 분명해졌지만 수면 메서드는 거의 유용하지 않습니다. 더 많은 실제 사례가 필요합니다.

파일 다운로드 테스트

파일을 다운로드하고 저장하는 프로세스를 실행합니다.

"net/http" 필요

다운로드 파일 테스트 클래스 < 테스트
  def perform
    Net::HTTP.get("upload.wikimedia.org", "/wikipedia/commons/thumb/7/73/Ruby_logo.svg/2000px-Ruby_logo.svg.png")
  end
end

다음 결과에 대해서는 따로 설명할 필요가 없습니다. 위의 예와 매우 유사합니다.

1.003642JRuby루비니우스
순차적0.3279800.3340000.329353
포크0.104766–0.121054
스레딩0.0857890.0940000.088490

또 다른 좋은 예로는 파일 복사 프로세스나 기타 I/O 작업을 들 수 있습니다.

결론

  • 루비니우스 는 포크와 스레딩을 모두 완벽하게 지원합니다(GIL이 제거된 버전 2.X부터). 코드를 동시에 실행하거나 병렬로 실행할 수 있습니다.
  • JRuby 는 스레드를 잘 처리하지만 포킹을 전혀 지원하지 않습니다. 스레드를 사용하면 병렬성과 동시성을 달성할 수 있습니다.
  • MRI 는 포크를 지원하지만 GIL의 존재로 인해 스레딩이 제한됩니다. 스레드를 사용하면 동시성을 달성할 수 있지만 실행 중인 코드가 루비 인터프리터 컨텍스트(예: IO 연산, 커널 함수)를 벗어나는 경우에만 가능합니다. 병렬성을 달성할 수 있는 방법은 없습니다.

관련 문서

소프트웨어 개발

미래 지향적인 웹 앱 구축: The Codest의 전문가 팀이 제공하는 인사이트

The Codest가 최첨단 기술로 확장 가능한 대화형 웹 애플리케이션을 제작하고 모든 플랫폼에서 원활한 사용자 경험을 제공하는 데 탁월한 성능을 발휘하는 방법을 알아보세요. Adobe의 전문성이 어떻게 디지털 혁신과 비즈니스를 촉진하는지 알아보세요...

최신
소프트웨어 개발

라트비아에 본사를 둔 10대 소프트웨어 개발 기업

최신 기사에서 라트비아 최고의 소프트웨어 개발 기업과 그들의 혁신적인 솔루션에 대해 알아보세요. 이러한 기술 리더들이 어떻게 귀사의 비즈니스를 향상시키는 데 도움을 줄 수 있는지 알아보세요.

thecodest
엔터프라이즈 및 스케일업 솔루션

Java 소프트웨어 개발 필수 사항: 성공적인 아웃소싱을 위한 가이드

The Codest로 효율성을 높이고 전문 지식을 활용하며 프로젝트 성공을 이끌 수 있는 성공적인 outsourcing Java 소프트웨어 개발에 대한 이 필수 가이드를 살펴보세요.

thecodest
소프트웨어 개발

폴란드 아웃소싱을 위한 최고의 가이드

폴란드에서 outsourcing가 급증한 것은 경제, 교육, 기술 발전으로 인한 IT 성장과 비즈니스 친화적인 환경이 조성된 덕분입니다.

더코데스트
엔터프라이즈 및 스케일업 솔루션

IT 감사 도구 및 기술에 대한 완벽한 가이드

IT 감사는 안전하고 효율적이며 규정을 준수하는 시스템을 보장합니다. 전체 기사를 읽고 그 중요성에 대해 자세히 알아보세요.

The Codest
야쿱 야쿠보비치 CTO & 공동 설립자

지식창고를 구독하고 IT 분야의 전문 지식을 최신 상태로 유지하세요.

    회사 소개

    The Codest - 폴란드에 기술 허브를 둔 국제 소프트웨어 개발 회사입니다.

    영국 - 본사

    • 사무실 303B, 182-184 하이 스트리트 노스 E6 2JA
      영국 런던

    폴란드 - 현지 기술 허브

    • 파브리츠나 오피스 파크, 알레야
      포코주 18, 31-564 크라쿠프
    • 뇌 대사관, 콘스트럭터스카
      11, 02-673 바르샤바, 폴란드

      The Codest

    • 홈
    • 회사 소개
    • 서비스
    • Case Studies
    • 방법 알아보기
    • 채용 정보
    • 사전

      서비스

    • IT 자문
    • 소프트웨어 개발
    • 백엔드 개발
    • 프론트엔드 개발
    • Staff Augmentation
    • 백엔드 개발자
    • 클라우드 엔지니어
    • 데이터 엔지니어
    • 기타
    • QA 엔지니어

      리소스

    • 외부 소프트웨어 개발 파트너와의 협력에 대한 사실과 오해
    • 미국에서 유럽으로: 미국 스타트업이 유럽으로 이전을 결정하는 이유
    • 테크 오프쇼어 개발 허브 비교: 테크 오프쇼어 유럽(폴란드), 아세안(필리핀), 유라시아(터키)
    • CTO와 CIO의 주요 과제는 무엇인가요?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • 웹사이트 이용 약관

    저작권 © 2025 by The Codest. 모든 권리 보유.

    ko_KRKorean
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese es_ESSpanish nl_NLDutch etEstonian elGreek ko_KRKorean