0Pricing
Ruby Academy · レッスン

GVL の解説

スレッドに制限がある理由です。

「GVL の解説」はCoddyKit上の無料Ruby Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはRuby Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Ruby Academyコースには全4レッスンが含まれています。

GVLとは何ですか

GVL(グローバルVMロック。歴史的にはGIL)は、標準RubyインタープリターであるCRuby内部のロックです。

  • 一度に1つのスレッドだけがRubyコードを実行できるようにします。
  • インタープリターの内部状態が並行実行によって破壊されるのを防ぎます。
  • 純粋なRubyのCPU処理は、複数のコアで真の並列実行にならないことを意味します。

GVLを理解すると、スレッドが役立つ場面と、役立たない場面が分かります。

なぜ存在するのか

CRubyの内部処理(オブジェクトの割り当て、ガベージコレクション、C拡張)のすべてが、スレッドセーフになるように作られているわけではありません。GVLはRubyの実行を直列化することで、それらを安全にします。

GVLをきれいに取り除くのは難しいため、CRubyでは維持されています。JRubyとTruffleRubyにはGVLがなく、複数のコアでスレッドを実行できます。

CPUバウンドな処理

CPUバウンドなタスク(数学計算、ソート、解析)では、CRubyのもとでスレッドを使っても処理は速くなりません。どの瞬間にもRubyコードを実行できるスレッドは1つだけなので、2つのCPUスレッドを使っても、おおむね1つのスレッドにオーバーヘッドが加わった状態になります。

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

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

I/OはGVLを解放する

重要なポイントは、ブロッキングI/OがGVLを解放することです。スレッドがスリープしたり、ファイルを読み取ったり、ソケットを待機したりすると、ロックを手放すため、別のスレッドがRubyを実行できます。

GVLがあっても、スレッドがI/Oバウンドな処理に適しているのはこのためです。

待機処理の重複

ここでは3つのスレッドがそれぞれスリープします。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を解放できます。これにより、Rubyのスレッドが処理を続けている間も、負荷の高いネイティブ処理を並列実行できます。

そのため、CRuby上でも真の並列性を実現できるライブラリがあります。

スレッドは切り替わり続ける

CPU処理であっても、GVLが他のスレッドを永遠に停止させるわけではありません。CRubyは定期的にスレッドを強制的に切り替え、それぞれに順番を与えます。この処理は並行(交互に実行)ですが、並列(同時に実行)ではありません。

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(", ")

並行性と並列性

重要な用語が2つあります。

  • 並行性:タスクが交互に実行されることで進行します。GVLはこれを可能にします。
  • 並列性:異なるコア上でタスクがまったく同じ瞬間に実行されます。GVLはRubyコードでこれを妨げます。

スレッドは並行性を、Ractorは並列性を提供します。

GVLを回避する方法

CRubyでCPU処理に複数のコアを使うには、次の方法があります。

  • 複数のプロセスを実行する(各プロセスが独自のGVLを持ちます)。
  • プロセス内の並列実行にRactorを使う。
  • GVLを解放するC拡張に処理を委譲する。

I/O処理では、通常のスレッドで十分なことが多いです。

プロセスはGVLを共有しない

各OSプロセスは、独自のGVLを持つ独自のRuby VMを実行します。フォークすると真の並列性を実現できますが、プロセス同士はメモリを共有せず、より多くのリソースを使用します。

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

戦略の選び方

判断の目安:

  • 待機が多い場合:スレッドを使います。
  • CPU負荷が高く、コアを活用したい場合:プロセスまたはRactorを使います。
  • 状態を共有する必要がある場合:Mutexを使ったスレッドを選びます。ただし、GVLによる制限に注意してください。

GVLを理解しておくと、CPUスレッドの性能がコア数に比例して向上すると期待してしまう、典型的な誤りを防げます。

確認問題

GVLについての理解度を確認しましょう。

まとめ:GVL

グローバルVMロックについて押さえておきたいポイント:

  • CRubyでは、一度に1つのスレッドだけがRubyコードを実行します。
  • インタープリターの内部状態を保護します。
  • ブロッキングI/Oによって解放されるため、待機処理を重ねて実行できます。
  • CPUバウンドなRuby処理は、複数のコアにまたがって並列化されません。
  • 真の並列性にはプロセスまたはRactorを使います。

次は、軽量な協調的並行性を実現するファイバーについて学びます。

よくある質問

「GVL の解説」レッスンは無料ですか?

はい。「GVL の解説」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Ruby Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Ruby Academyコースには全4レッスンが含まれています。

「GVL の解説」で何を学びますか?

スレッドに制限がある理由です。 ブラウザで直接実行するハンズオンコードでRuby Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Ruby Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのRuby Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「GVL の解説」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このRuby Academyレッスンでコードを書いて実行できますか?

はい。すべてのRuby Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. スレッド
  2. GVL の解説
  3. Fiber
  4. Ractor
← Ruby Academyに戻る