0Pricing
Ruby Academy · レッスン

スレッド

並行実行です。

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

スレッドとは何ですか

スレッドは、プログラム内で独立して実行される経路です。Rubyでは複数のスレッドを実行して、処理を時間的に重ねて進められます。

  • メインプログラムはメインスレッドで実行されます。
  • Thread.newでスレッドを追加できます。
  • スレッドは同じメモリを共有するため、同じ変数を読み書きできます。

プログラムが待機(ネットワーク、ディスク、スリープ)に時間を使う場合、スレッドが特に役立ちます。一方のスレッドが待機している間に、別のスレッドが処理を続けられるためです。

スレッドの作成

Thread.newにブロックを渡します。ブロックは新しいスレッドで実行されます。プログラムが終了する前にスレッドの完了を待つには、joinを呼び出します。

t = Thread.new do
  puts "Hello from the new thread"
end

t.join
puts "Main thread done"

joinが重要な理由

メインスレッドが終了するとRubyも終了するため、他のスレッドを待たない場合があります。joinは、対象のスレッドが完了するまで呼び出し元をブロックします。

joinがないと、プログラムが終了する前にワーカースレッドが出力する機会を得られない可能性があります。

t = Thread.new do
  sleep 0.1
  puts "Worker finished"
end

puts "Waiting..."
t.join
puts "All done"

複数のスレッドを同時に実行

複数のスレッドを起動して配列にまとめ、それぞれに対してjoinを呼び出せます。これは、I/O処理を擬似的に並列化するときによく使われるパターンです。

threads = (1..3).map do |n|
  Thread.new do
    puts "Thread number " + n.to_s
  end
end

threads.each(&:join)
puts "Finished all threads"

変数の共有

スレッドはメモリを共有します。スレッドの前に定義した変数は、そのスレッド内から参照できます。これは強力な仕組みですが、2つのスレッドが同じ値を書き込む場合は危険でもあります。

counter = 0

t = Thread.new do
  counter += 1
end

t.join
puts "Counter is " + counter.to_s

競合状態

競合状態は、スレッドが共有データへの更新を交互に実行し、結果がタイミングに依存するときに発生します。

  • counter += 1は、実際には読み取り、加算、書き込みという処理です。
  • 2つのスレッドが同じ古い値を読み取り、同じ新しい値を書き込むと、片方の加算が失われる可能性があります。

この問題は、ロックでアクセスを調整すると解決できます。

Mutex:ロック

Mutex(相互排他)は、保護対象のコードを一度に1つのスレッドだけが実行できるようにします。クリティカルセクションをmutex.synchronizeで囲みます。

mutex = Mutex.new
counter = 0

threads = (1..5).map do
  Thread.new do
    mutex.synchronize do
      counter += 1
    end
  end
end

threads.each(&:join)
puts "Counter is " + counter.to_s

値を返す

Thread#valueはスレッドの完了を待ち、そのブロックの値を返します。自動的にjoinを呼び出し、さらに結果も返すような仕組みです。

t = Thread.new do
  2 + 3
end

puts "Result is " + t.value.to_s

スレッドローカル変数

各スレッドは、Thread.current[:key]を使ってシンボルをキーにした独自の値を保存できます。これらの値はそのスレッド専用で、共有されることはありません。

t = Thread.new do
  Thread.current[:name] = "worker"
  puts "Inside: " + Thread.current[:name]
end

t.join

例外の処理

スレッドでエラーが発生しても、joinまたはvalueを呼び出すまでは通知されません。これらを呼び出すとエラーが再発生します。Thread.abort_on_exception = trueを設定すると、エラーが直ちにプログラム全体をクラッシュさせるため、デバッグに役立ちます。

t = Thread.new do
  raise "boom"
end

begin
  t.join
rescue => e
  puts "Caught: " + e.message
end

スレッドが役立つ場面

スレッドは、待機に時間を使うI/Oバウンドな処理で特に力を発揮します。一方、CPUバウンドな処理では、次に説明するGVLのため、効果は限定的です。

  • 適している例:多数のURLのダウンロード、多数のファイルの読み込み
  • 効果が限定的な例:複数のコアを使った負荷の高い数値計算

共有する可変状態は、必ずMutexで保護してください。

確認問題

スレッドについての理解度を確認しましょう。

まとめ:スレッド

Rubyのスレッドについて、次の基本を学びました。

  • Thread.newは並行実行を開始します。
  • joinは完了を待ち、valueは完了を待って結果を返します。
  • スレッドはメモリを共有するため、競合状態が発生することがあります。
  • synchronizeを使ったMutexは共有状態を保護します。
  • スレッドはI/Oバウンドな処理で力を発揮します。

次は、スレッドが複数のCPUコアを完全には使えない理由であるGVLについて学びます。

よくある質問

「スレッド」レッスンは無料ですか?

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

「スレッド」で何を学びますか?

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

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

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

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

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

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

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

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

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