0Pricing
Ruby Academy · 강의

GVL 해설

스레드가 제한되는 이유를 알아봅니다

GVL 해설은(는) CoddyKit의 무료 Ruby Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Ruby Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Ruby Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

GVL이란 무엇인가요

GVL(전역 VM 잠금, 역사적으로는 GIL)은 표준 루비 인터프리터인 씨루비 내부의 잠금입니다.

  • 한 번에 하나의 스레드만 루비 코드를 실행할 수 있도록 합니다.
  • 인터프리터의 내부 구현이 동시에 실행되면서 손상되지 않도록 보호합니다.
  • 순수 루비의 CPU 작업이 여러 코어에서 실제로 병렬 실행되지 않게 합니다.

GVL을 이해하면 스레드가 언제 도움이 되고 언제 도움이 되지 않는지 알 수 있습니다.

존재하는 이유

씨루비의 내부 구성 요소(객체 할당, 가비지 컬렉션, C 확장 기능)는 모두 스레드 안전을 고려하여 작성된 것은 아니었습니다. GVL은 루비 실행을 직렬화하여 이를 안전하게 만듭니다.

GVL을 깔끔하게 제거하기는 어렵기 때문에 씨루비는 이를 유지합니다. 제이루비와 TruffleRuby에는 GVL이 없으므로 여러 코어에서 스레드를 실행할 수 있습니다.

CPU 중심 작업

CPU 중심 작업(수학 계산, 정렬, 구문 분석)에서는 씨루비의 GVL 때문에 스레드가 작업 속도를 높이지 못합니다. 어떤 순간에도 하나의 스레드만 루비 코드를 실행하므로 CPU 스레드 두 개를 사용해도 대략 스레드 하나에 오버헤드만 추가된 결과와 같습니다.

def heavy
  sum = 0
  1_000_00.times { |i| sum += i }
  sum
end

puts heavy
puts "CPU work does not parallelize under the GVL"

입출력이 GVL을 해제하는 방식

핵심은 차단 입출력이 GVL을 해제한다는 점입니다. 스레드가 일시 중지하거나 파일을 읽거나 소켓을 기다릴 때 잠금을 놓아 다른 스레드가 루비를 실행할 수 있게 합니다.

GVL이 있어도 스레드가 입출력 중심 작업에 뛰어난 이유가 바로 이것입니다.

대기 겹쳐 실행하기

여기서는 세 스레드가 각각 잠시 일시 중지합니다. sleep이 GVL을 해제하므로 대기 시간이 겹칩니다. 전체 시간은 0.6초가 아니라 약 0.2초입니다.

start = Time.now

threads = (1..3).map do
  Thread.new { sleep 0.2 }
end
threads.each(&:join)

elapsed = Time.now - start
puts "Elapsed roughly: " + elapsed.round(1).to_s

C 확장 기능은 GVL을 해제할 수 있습니다

잘 작성된 C 확장 기능은 rb_thread_call_without_gvl을 사용하여 긴 네이티브 계산을 수행하는 동안 GVL을 해제할 수 있습니다. 이렇게 하면 루비 스레드가 계속 실행되는 동안 대규모 네이티브 작업을 병렬로 실행할 수 있습니다.

따라서 일부 라이브러리는 씨루비에서도 실제 병렬성을 구현합니다.

스레드는 여전히 전환됩니다

CPU 작업을 수행할 때도 GVL이 다른 스레드를 영원히 멈추게 하지는 않습니다. 씨루비는 주기적으로 스레드를 선점하여 각 스레드가 차례를 얻도록 합니다. 작업은 동시적(서로 끼워 실행됨)이지만 병렬적(동시에 실행됨)이지는 않습니다.

results = []
mutex = Mutex.new

threads = (1..3).map do |n|
  Thread.new do
    mutex.synchronize { results << n }
  end
end
threads.each(&:join)

puts "Collected: " + results.sort.join(", ")

동시성과 병렬성 비교

중요한 두 용어를 알아봅시다.

  • 동시성: 작업이 서로 끼워 실행되면서 진행되는 방식입니다. GVL은 이를 허용합니다.
  • 병렬성: 서로 다른 코어에서 작업이 정확히 같은 순간에 실행되는 방식입니다. GVL은 루비 코드에서 이를 막습니다.

스레드는 동시성을 제공하고, 랙터는 병렬성을 제공합니다.

GVL 우회하기

씨루비에서 CPU 작업에 여러 코어를 사용하려면 다음 방법을 사용할 수 있습니다.

  • 여러 프로세스를 실행합니다(각 프로세스에는 자체 GVL이 있습니다).
  • 프로세스 내부 병렬성에 랙터를 사용합니다.
  • GVL을 해제하는 C 확장 기능에 작업을 맡깁니다.

입출력 작업에는 일반 스레드만으로도 대개 충분합니다.

프로세스는 GVL을 공유하지 않습니다

각 OS 프로세스는 자체 GVL이 있는 자체 루비 VM을 실행합니다. 포크를 사용하면 실제 병렬성을 얻을 수 있지만, 프로세스는 메모리를 공유하지 않으며 더 많은 자원을 사용합니다.

puts "Main pid: " + Process.pid.to_s
puts "Each forked process has its own independent GVL"

전략 선택하기

판단 안내:

  • 대기할 일이 많나요? 스레드를 사용합니다.
  • CPU 작업이 많고 코어를 활용하고 싶나요? 프로세스 또는 랙터를 사용합니다.
  • 공유 상태가 필요한가요? Mutex와 함께 스레드를 사용하되 GVL의 제약에 유의합니다.

GVL을 이해하면 CPU 스레드의 성능이 선형적으로 확장될 것이라고 기대하는 흔한 실수를 피할 수 있습니다.

간단 확인

GVL에 대한 이해도를 확인해 보세요.

복습: GVL

전역 VM 잠금에 대해 기억할 핵심 내용입니다.

  • 씨루비에서는 한 번에 하나의 스레드만 루비 코드를 실행합니다.
  • 인터프리터의 내부 구현을 보호합니다.
  • 차단 입출력은 GVL을 해제하여 대기 시간을 겹칠 수 있게 합니다.
  • CPU 중심 루비 작업은 여러 코어에서 병렬화되지 않습니다.
  • 실제 병렬성을 얻으려면 프로세스 또는 랙터를 사용합니다.

다음에는 가벼운 협력적 동시성을 제공하는 파이버를 살펴봅니다.

자주 묻는 질문

“GVL 해설” 강의는 무료인가요?

네 — “GVL 해설” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Ruby Academy 강의 전체를 잠금 해제할 수 있습니다. Ruby Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“GVL 해설”에서 뭘 배우나요?

스레드가 제한되는 이유를 알아봅니다 브라우저에서 직접 실행하는 실습 코드로 Ruby Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Ruby Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Ruby Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“GVL 해설” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Ruby Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Ruby Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 스레드
  2. GVL 해설
  3. 파이버
  4. Ractor
← Ruby Academy(으)로 돌아가기