Latest web development tutorials

Rubyのマルチスレッド

システム上で実行されている各プログラムは、プロセスです。 各プロセスは、1つまたは複数のスレッドが含まれています。

スレッドは、マルチスレッドと呼ばれる、別のことを行うと同時に、単一のプログラムで複数のスレッドを実行して、単一の逐次プログラムの制御フローです。

ルビー、我々は複数のスレッドのThreadクラスによって作成することができ、Rubyのスレッドは、それが並列コードを実装するための効率的な方法することができ、軽量です。


Rubyのスレッドを作成します

新しいスレッドを開始するには、あなただけのThread.newを呼び出すことができます。

# 线程 #1 代码部分
Thread.new {
  # 线程 #2 执行代码
}
# 线程 #1 执行代码

次の例では、Rubyプログラムでマルチスレッドを使用する方法を示しています。

#!/usr/bin/ruby

def func1
   i=0
   while i<=2
      puts "func1 at: #{Time.now}"
      sleep(2)
      i=i+1
   end
end

def func2
   j=0
   while j<=2
      puts "func2 at: #{Time.now}"
      sleep(1)
      j=j+1
   end
end

puts "Started At #{Time.now}"
t1=Thread.new{func1()}
t2=Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"

上記のコードは、の結果として実行されます。

Started At Wed May 14 08:21:54 -0700 2014
func1 at: Wed May 14 08:21:54 -0700 2014
func2 at: Wed May 14 08:21:54 -0700 2014
func2 at: Wed May 14 08:21:55 -0700 2014
func1 at: Wed May 14 08:21:56 -0700 2014
func2 at: Wed May 14 08:21:56 -0700 2014
func1 at: Wed May 14 08:21:58 -0700 2014
End at Wed May 14 08:22:00 -0700 2014

スレッドのライフサイクル

1、スレッドがThread.newを使用することができます作成​​し、あなたはまた、スレッドを作成するために、同じ構文Thread.startまたはThread.fork三つの方法を使用することができます。

2、起動せずにスレッドを作成、スレッドが自動的に実行されます。

3、Threadクラスは、スレッドを操作するためのメソッドを定義します。 実行Thread.newコードブロックのスレッド。

4は、スレッドブロックは、スレッドの最後の文の値であり、スレッドは、スレッドが終了した場合は、スレッドの値を返す、またはスレッドが終了するまで値を返さない、方法によって呼び出すことができます。

5、Thread.current方法は、現在のスレッドの表現のためのオブジェクトを返します。 Thread.main方法は、メインスレッドを返します。

図6に示すように、方法は、Thread.Joinスレッドによって実行され、現在のスレッドが終了するまで、この方法は、メインスレッドを一時停止します。


スレッド状態

スレッドは、5つの状態があります。

スレッド状態 戻り値
実行ファイル ラン
睡眠 睡眠
やめます 中止
正常終了
異常終了が発生します ゼロ

スレッドと異常

スレッドの例外が発生し、何の救済がキャプチャされなかった場合には、スレッドが正常に警告なしに終了することになります。 関係は、このスレッドを待っているので、他のスレッドのスレッド#が参加する場合は、その後、待機中のスレッドは、同じ例外が発生します。

begin
  t = Thread.new do
    Thread.pass    # 主线程确实在等join
    raise "unhandled exception"
  end
  t.join
rescue
  p $!  # => "unhandled exception"
end

あなたは、スレッドが例外による終了したときの動作を中断するインタプリタを得ることができ、次の3つの方法を使用してください。

  • スタートアップスクリプトは-dオプション、およびデバッグモードの動作を指定します。
  • Thread.abort_on_exceptionフラグを設定します。
  • 使用するThread#abort_on_exception指定されたスレッドセットフラグを。

上述の3つの方法のいずれかを使用する場合、全体のインタプリタは中断されます。

t = Thread.new { ... }
t.abort_on_exception = true

スレッド同期

Rubyでは、すなわち、3同期した方法を提供します。

1.ミューテックスクラスは、スレッドの同期を実装します

2.規制データ転送キュークラススレッドの同期を実現します

3. ConditionVariable同期制御

ミューテックスクラスによってスレッドの同期を実装

あなたはまた、複数のスレッド内のプログラム可変クロックが必要な場合は、ミューテックスクラスによって、スレッド同期制御を実装するには、可変部分をロックするためにロックを使用することができます。 次のようにコードは次のとおりです。

#!/usr/bin/ruby

require "thread"
puts "Synchronize Thread"

@num=200
@mutex=Mutex.new

def buyTicket(num)
     @mutex.lock
          if @num>=num
               @num=@num-num
               puts "you have successfully bought #{num} tickets"
          else
               puts "sorry,no enough tickets"
          end
     @mutex.unlock
end

ticket1=Thread.new 10 do
     10.times do |value|
     ticketNum=15
     buyTicket(ticketNum)
     sleep 0.01
     end
end

ticket2=Thread.new 10 do
     10.times do |value|
     ticketNum=20
     buyTicket(ticketNum)
     sleep 0.01
     end
end

sleep 1
ticket1.join
ticket2.join

上記のコードは、の結果として実行されます。

Synchronize Thread
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets

変数をロックし、ロックを使用することに加えて、あなたもtry_lockロックされた変数を使用することができます、またMutex.synchronizeは、特定の変数へのアクセスを同期使用することができます。

キュークラスの規制データ転送は、スレッド同期を実装します

糸支持キューを表すキュークラスは、キューは、訪問の終わりに同期させることができます。 異なるスレッドは、統合クラスを使用することができますが、SizedQueueクラスキュー長の使用を制限することに加えて、データはこのキューに同期させることができるかどうか心配しないでください

SizedQueueクラスは、私たちは同期させるためのスレッド・アプリケーションの開発を支援するために非常に便利なことができ、同期の問題は、長いキューに追加する必要があり、あなたがスレッドを気にしないでください。

クラシック生産者と消費者:

#!/usr/bin/ruby

require "thread"
puts "SizedQuee Test"

queue = Queue.new

producer = Thread.new do
     10.times do |i|
          sleep rand(i) # 让线程睡眠一段时间
          queue << i
          puts "#{i} produced"
     end
end

consumer = Thread.new do
     10.times do |i|
          value = queue.pop
          sleep rand(i/2)
          puts "consumed #{value}"
     end
end

consumer.join

プログラムの出力:

SizedQuee Test
0 produced
1 produced
consumed 0
2 produced
consumed 1
consumed 2
3 produced
consumed 34 produced

consumed 4
5 produced
consumed 5
6 produced
consumed 6
7 produced
consumed 7
8 produced
9 produced
consumed 8
consumed 9

スレッド変数

スレッドには、プライベート変数、スレッドが作成されたスレッドプライベート変数の書き込みスレッドを持つことができます。 これは、スレッドの範囲内で使用することができますが、スレッドは、外部共有することはできません。

しかし、時には、スレッドローカル変数は、別のスレッドまたは実行する方法をアクセスするためにメインスレッドを必要としませんか? ルビーは、スレッドが同じようなスタイルハッシュハッシュテーブルとして見られている、彼らはスレッドが変数名によって提供されて作成することができます。 [] = []データを読み込むことによって書かれたことで。 私たちは、次のコードを見て:

#!/usr/bin/ruby

count = 0
arr = []

10.times do |i|
   arr[i] = Thread.new {
      sleep(rand(0)/10.0)
      Thread.current["mycount"] = count
      count += 1
   }
end

arr.each {|t| t.join; print t["mycount"], ", " }
puts "count = #{count}"

上記のコードは出力され実行されます。

8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10

子スレッドの実行のためにメインスレッドが待機を完了し、各値を出力します。 。


スレッドの優先順位

スレッドの優先順位は、スレッドのスケジューリングに影響を与える主な要因です。 他の要因は、CPUスレッドパケットスケジューリングとを実行するための時間の長さを含みます。

あなたはThread.priorityを使用することができますスレッドの優先順位を取得し、スレッドの優先度を調整するThread.priority =メソッドを使用します。

0にスレッドの優先順位のデフォルト値。 優先度の高い実行速度が速く。

スレッドは、独自の範囲内のすべてのデータにアクセスできますが、他のスレッドがスレッド内のデータにアクセスする必要がある場合はそれを行う方法をすべきですか? Threadクラスは、スレッドのデータが相互にアクセス提供し、あなたは、単にハッシュテーブルとしてスレッドを置くことができ、任意のスレッド[] =書き込みデータで使用することができ、データを読み込む[]を使用します。

athr = Thread.new { Thread.current["name"] = "Thread A"; Thread.stop }
bthr = Thread.new { Thread.current["name"] = "Thread B"; Thread.stop }
cthr = Thread.new { Thread.current["name"] = "Thread C"; Thread.stop }
Thread.list.each {|x| puts "#{x.inspect}: #{x["name"]}" }

私たちは、ハッシュテーブルのようなスレッドを参照してくださいに[]と[] =メソッドは、我々は、スレッド間のデータ共有を実現することができます。


スレッドのミューテックス

ミューテックス(Mutal除外=ミューテックス)は、マルチスレッドプログラミング、読み出しおよび書き込み(グローバル変数等)同じ公共資源のために、同時に2つのスレッドを防止するためのメカニズムのための方法です。

不使用Mutaxの例

#!/usr/bin/ruby
require 'thread'

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      count1 += 1
      count2 += 1
   end
end
spy = Thread.new do
   loop do
      difference += (count1 - count2).abs
   end
end
sleep 1
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

上の例の出力は実行します。

count1 :  9712487
count2 :  12501239
difference : 0

Mutaxの例

#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      mutex.synchronize do
         count1 += 1
         count2 += 1
      end
    end
end
spy = Thread.new do
   loop do
       mutex.synchronize do
          difference += (count1 - count2).abs
       end
   end
end
sleep 1
mutex.lock
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

上の例の出力は実行します。

count1 :  1336406
count2 :  1336406
difference : 0

デッドロック

他のパーティーに早期終了を、実行を停止するためにシステムリソースを取得することではなく、ために二つ以上の演算ユニットは、両側が待っている、このような状況は、デッドロックと呼ばれています。

あなたは、プリンタを使用する必要がありながら、例えば、プロセスp1は、ディスプレイを占めており、プリンタがプロセスP2によって占有されている、p2はまた、このようにして、デッドロックを形成し、モニターを使用する必要があります。

我々はミューテックスを使用すると、オブジェクトは、注目スレッドのデッドロックを必要とします。

#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

cv = ConditionVariable.new
a = Thread.new {
   mutex.synchronize {
      puts "A: I have critical section, but will wait for cv"
      cv.wait(mutex)
      puts "A: I have critical section again! I rule!"
   }
}

puts "(Later, back at the ranch...)"

b = Thread.new {
   mutex.synchronize {
      puts "B: Now I am critical, but am done with cv"
      cv.signal
      puts "B: I am still critical, finishing up"
   }
}
a.join
b.join

上の例の出力は、次のとおりです。

A: I have critical section, but will wait for cv
(Later, back at the ranch...)
B: Now I am critical, but am done with cv
B: I am still critical, finishing up
A: I have critical section again! I rule!

Threadクラスのメソッド

完全なスレッド(スレッド)クラスメソッドを次のように

いいえ。 メソッド説明
1 Thread.abort_on_exception
スレッドが終了したら、それは例外のため、trueの場合、全体のインタプリタが中断されます。 スレッドの例外が発生した場合、デフォルト値は、通常の状況下で、つまり、偽であり、例外が検出された#が参加通し、他のされていない、スレッドは警告なしに終了します。
2 Thread.abort_on_exception =
trueに設定されている場合は例外に、全体のインタプリタが中断されるため一度スレッドが終了します。 新しい状態を返します。
3 Thread.critical
ブール値を返します。
4 Thread.critical =
値がtrueの場合、スレッドは切り替わりません。 現在のスレッドが(停止)または信号(シグナル)の介入がハングアップする場合は、その値は自動的にfalseに変更されます。
5 Thread.current
現在実行中のスレッド(現在のスレッドを)返します。
6 Thread.exit
これは、現在のスレッドを終了します。 現在のスレッドを返します。 現在のスレッドがその動作を終了するには、exit(0)を使用して、唯一のスレッドである場合。
7 Thread.fork {ブロック}
Thread.newと同様にスレッドを生成します。
8 Thread.kill(aThread)
スレッドの実行を終了します。
9 Thread.list
ライブスレッドのアレイが実行しているかの状態を中断され返します。
10 Thread.main
メインスレッドに戻ります。
11 Thread.new([引数] *){ |引数|ブロック}
スレッドを生成し、実行を開始します。 数がブロックにそのまま渡されます。これは、同時にスレッドを開始することができ、値はスレッドに固有のローカル変数に渡されます。
12 Thread.pass
他のスレッドを実行する権利。それは、実行中のスレッドの状態を変更しませんが、他のスレッドの制御を引き渡すますが(明示的なスレッドスケジューリング)を実行することができます。
13 Thread.start([引数] *){ |引数|ブロック}
スレッドを生成し、実行を開始します。 数がブロックにそのまま渡されます。これは、同時にスレッドを開始することができ、値はスレッドに固有のローカル変数に渡されます。
14 Thread.stop
メソッドを実行する他のスレッドが再びスレッドを覚ますまで、現在のスレッドは中断されます。

スレッドのインスタンスメソッド

次の例では、スレッドのインスタンスメソッドが参加呼び出します。

#!/usr/bin/ruby

thr = Thread.new do   # 实例化
   puts "In second thread"
   raise "Raise exception"
end
thr.join   # 调用实例化方法 join

ここでは方法の例の完全なリストは、次のとおりです。

いいえ。 メソッド説明
1 THR [名前]
固有のデータに対応する名前のスレッドを削除します。 名前は、文字列や記号をすることができます。 名前がデータに対応していない場合は、nilを返します。
2 THR [名] =
対応する特性データ内のスレッド名の値を設定し、名前が文字列や記号をすることができます。 nilに設定した場合、このスレッドで対応するデータを削除します。
3 thr.abort_on_exception
ブール値を返します。
4 thr.abort_on_exception =
その値がtrueの場合、スレッドが例外による終了したら、次に、全体のインタプリタは中断されます。
5 thr.alive?
スレッドは「ライブ」である場合、それはtrueを返します。
6 thr.exit
スレッドの実行を終了します。 自己を返します。
7 thr.join
スレッドが終了するまで、自己の実行まで、現在のスレッドを中断します。による異常終了に自己場合は、現在のスレッドが同じ例外をトリガします。
8 thr.key?
固有のデータに対応する名前がスレッドを定義されている場合は、trueを返します
9 thr.kill
同様Thread.exit。
10 thr.priority
スレッドの優先順位を返します。デフォルトの優先度は0より大きい値、優先度が高いです。
11 thr.priority =
スレッドの優先順位を設定する。また、負に設定することができます。
12 thr.raise(anException)
このスレッド内に強制的にスローされました。
13 thr.run
保留(停止)スレッドを再起動します。違いは、ウェイクアップしてスレッド直ちに切り替えを実施することである。この方法を使用すると、死者はThreadError例外を発生します処理する場合。
14 thr.safe_level
自己のセキュリティレベルを返します。Safe_level同じ現在のスレッドの$ SAFE。
15 thr.status
スレッドが正常に終了した場合、文字列「実行」、「スリープ」または「中止」を使用すると、それはfalseを返し、ライブスレッドの状態を示します。Ruoyin異常終了し、それはnilを返します。
16 thr.stop?
スレッドは、状態(死)を終了するか、(停止)真のリターンを一時停止している場合。
17 thr.value
自己スレッドが終了するまで待ちます(等価が参加する)、実行中のスレッドが異常時に発生した場合、スレッドのブロックの値を返し、例外が再び発生します。
18 thr.wakeup
メソッドがThreadError例外が発生しますデッドスレッド上で実行される場合状態は、レディ状態(RUN)のスレッドの(停止)に懸濁されます。