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 { ja. } 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 ranchja.)" 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 ranchja.) 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)のスレッドの(停止)に懸濁されます。 |