柚子快報邀請碼778899分享:無涯教程-Ruby - 多線程
柚子快報邀請碼778899分享:無涯教程-Ruby - 多線程
傳統(tǒng)程序只有一個執(zhí)行線程,構(gòu)成該程序的語句或指令將順序執(zhí)行,直到程序終止。
多線程程序具有多個執(zhí)行線程。在每個線程中,語句是按順序執(zhí)行的,但是線程本身可以在如多核CPU上并行執(zhí)行。通常在單個CPU計算機上,實際上不是并行執(zhí)行多個線程,而是通過交錯執(zhí)行線程來模擬并行性。
Ruby使使用 Thread 類編寫多線程程序變得容易。 Ruby線程是在代碼中實現(xiàn)并發(fā)的輕量級高效方法。
創(chuàng)建線程
要啟動新線程,只需將一個塊與對 Thread.new的調(diào)用相關(guān)聯(lián)。將創(chuàng)建一個新線程來執(zhí)行塊中的代碼,原始線程將立即從 Thread.new 返回并使用下一條語句恢復(fù)執(zhí)行-
# Thread #1 is running here
Thread.new {
# Thread #2 runs this code
}
# Thread #1 runs this code
這是一個示例,顯示了如何使用多線程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}"
這將產(chǎn)生以下輸出-
Started At 2021-03-09 00:15:08 +0800
func1 at: 2021-03-09 00:15:08 +0800
func2 at: 2021-03-09 00:15:08 +0800
func2 at: 2021-03-09 00:15:09 +0800
func1 at: 2021-03-09 00:15:10 +0800
func2 at: 2021-03-09 00:15:10 +0800
func1 at: 2021-03-09 00:15:12 +0800
End at 2021-03-09 00:15:14 +0800
線程生命周期
使用 Thread.new?創(chuàng)建一個新線程。您還可以使用同義詞 Thread.start?和 Thread.fork?。
創(chuàng)建線程后無需啟動線程,它在CPU資源可用時自動開始運行。
Thread類定義了許多在線程運行時查詢和操作線程的方法。線程在與對 Thread.new的調(diào)用相關(guān)聯(lián)的塊中運行代碼,然后停止運行。
您可以通過調(diào)用特定線程的 Thread.join?方法來等待該線程完成。調(diào)用線程將阻塞,直到給定線程完成。
線程和異常
如果在主線程中引發(fā)了異常,并且沒有在任何地方處理異常,則Ruby解釋器將顯示一條消息并退出。在除主線程之外的其他線程中,未處理的異常會導(dǎo)致線程停止運行。
如果線程 t 由于未處理的異常而退出,而另一個線程 s 調(diào)用 t.join或t.value ,則發(fā)生的異常在 t 中在線程 s 中引發(fā)。
如果 Thread.abort_on_exception是 false (默認條件),則未處理的異常只會殺死當(dāng)前線程,其余所有線程繼續(xù)運行。
如果希望任何線程中任何未處理的異常導(dǎo)致解釋器退出,請將類方法 Thread.abort_on_exception?設(shè)置為 true 。
t=Thread.new { ... }
t.abort_on_exception=true
線程變量
創(chuàng)建線程時,線程通常可以訪問范圍內(nèi)的任何變量。線程塊本地的變量是線程本地的,并且不共享。
線程類具有特殊的函數(shù),該函數(shù)允許按名稱創(chuàng)建和訪問線程局部變量。您只需將線程對象視為哈希對象即可,使用[] =寫入元素,然后使用[]讀回它們。
在此示例中,每個線程都使用鍵 mycount 將變量計數(shù)的當(dāng)前值記錄在一個線程局部變量中。
#!/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}"
這產(chǎn)生以下輸出-
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count=10
主線程等待子線程完成,然后打印出每個子線程捕獲的 count 值。
線程優(yōu)先級
影響線程調(diào)度的第一個因素是線程優(yōu)先級:高優(yōu)先級線程先于低優(yōu)先級線程進行調(diào)度。更準(zhǔn)確地說,只有在沒有更高優(yōu)先級的線程等待運行時,線程才會獲得CPU時間。
您可以使用 priority=和 priority 設(shè)置和查詢Ruby Thread對象的優(yōu)先級。新創(chuàng)建的線程與創(chuàng)建它的線程具有相同的優(yōu)先級。主線程從優(yōu)先級0開始。
線程鎖
如果兩個線程共享對同一數(shù)據(jù)的訪問,并且至少有一個線程修改了該數(shù)據(jù),則必須格外小心,以確保沒有一個線程能夠看到處于不一致狀態(tài)的數(shù)據(jù)。這稱為線程排除。
Mutex 是一個實現(xiàn)簡單信號燈鎖的類,用于互斥訪問某些共享資源。也就是說,在給定的時間只有一個線程可以持有該鎖。其他線程可能選擇排隊等待該鎖可用,或者可能只是選擇立即獲得一個指示該鎖不可用的錯誤。
通過將對共享數(shù)據(jù)的所有訪問置于 mutex 的控制之下,無涯教程確保了一致性和原子操作。讓無涯教程嘗試示例,第一個不帶mutax,第二個帶mutax-
無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}"
這將產(chǎn)生以下輸出-
count1 : 1583766
count2 : 1583766
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}"
這將產(chǎn)生以下輸出-
count1 : 696591
count2 : 696591
difference : 0
處理死鎖
當(dāng)開始使用 Mutex 對象進行線程排除時,必須小心避免 deadlock 。死鎖是所有線程都在等待獲取另一個線程擁有的資源時發(fā)生的情況。由于所有線程均被阻止,因此它們無法釋放所持有的鎖。并且由于它們無法釋放鎖,因此其他線程也無法獲取這些鎖。
這是條件變量出現(xiàn)的地方。 條件變量只是與資源相關(guān)聯(lián)的信號量,并用于保護特定 mutex 。當(dāng)您需要不可用的資源時,請等待條件變量。該操作將釋放對相應(yīng) mutex 的鎖定。當(dāng)其他一些線程發(fā)出信號指示資源可用時,原始線程將退出等待狀態(tài),并同時重新獲得對關(guān)鍵區(qū)域的鎖定。
#!/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
這將產(chǎn)生以下輸出-
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!
線程狀態(tài)
下表顯示了與五個可能狀態(tài)相對應(yīng)的五個可能返回值。 status 方法返回線程的狀態(tài)。
線程狀態(tài)返回值Runnable運行中Sleeping休眠中Aborting已停止Terminated normally falseTerminated with exceptino nil
線程類方法
Thread 類提供了以下方法,它們適用于程序中所有可用的線程。這些方法將被稱為使用 Thread 類名,如下所示-
Thread.abort_on_exception=true
線程方法
這些方法適用于線程的。這些方法將被稱為使用 Thread 的,如下所示-
#!/usr/bin/ruby
thr=Thread.new do # Calling a class method new
puts "In second thread"
raise "Raise exception"
end
thr.join # Calling an instance method join
公開方法
MethodDescriptionabort_on_exception它返回全局“abort on exception”條件的狀態(tài)。默認值為true。設(shè)置為true時,如果任何線程中引發(fā)異常,則所有線程將中止。abort_on_exception=設(shè)置為true時,如果引發(fā)異常,則所有線程將中止。它返回新狀態(tài)。current它返回當(dāng)前正在執(zhí)行的線程。exclusive{block}它將塊包裝為單個,返回塊的值。exit它終止當(dāng)前正在運行的線程并安排另一個線程運行。kill(thread)它導(dǎo)致給定線程退出。fork([args]*){|args| block}它基本上與::new方法相同。handle_interrupt(hash){...}更改異步中斷時序。list返回可運行或已停止的所有線程的線程對象數(shù)組。main返回主線程。new{...}/ new(*args, &proc)/ new(*args){|args|...}它創(chuàng)建一個執(zhí)行給定塊的新線程。pass它為線程調(diào)度程序提供了將執(zhí)行傳遞給另一個線程的提示。正在運行的線程可能會切換,也可能不會切換,這取決于操作系統(tǒng)。pending_interrupt?(error = nil)它返回異步隊列是否為空。start([args]*){|args|block}它基本上與::new方法相同。stop它停止當(dāng)前線程的執(zhí)行,使其進入“sleep”睡眠狀態(tài)并計劃另一個線程的執(zhí)行。
公共實例方法
MethodDescriptionthr[sym]它使用字符串或符號名稱返回線程局部變量的值。thr[sym]=它使用字符串或符號名稱創(chuàng)建線程局部變量的值。abort_on_exception它返回線程的“異常終止”狀態(tài)。abort_on_exception=設(shè)置為true時,如果此線程中引發(fā)異常,則所有線程將中止。add_trace_func(proc)將proc添加為跟蹤處理程序。alive?如果線程正在運行或正在睡眠,則返回true。backtrace它返回當(dāng)前目標(biāo)的回溯。backtrace_locations(*args)它返回前面目標(biāo)的執(zhí)行堆棧。exit/kill/terminate它終止線程并執(zhí)行另一個線程來運行。group它返回包含給定線程的ThreadGroup或返回nil。inspect它將thr的名稱,id和狀態(tài)轉(zhuǎn)儲到字符串中。join調(diào)用線程將暫停執(zhí)行并運行此程序。key?(sym)如果給定的字符串作為線程局部變量存在,則返回true。keys它返回一個線程局部變量名稱的數(shù)組。pending_interrupt?(error=nil)返回異步隊列對于目標(biāo)線程是否為空。priority它返回線程的優(yōu)先級。priority=它將線程的優(yōu)先級設(shè)置為整數(shù)。kill它的作用與退出相同。raise它從給定線程中引發(fā)異常。run它喚醒線程,使它有資格進行調(diào)度。safe_level它返回線程有效的安全級別。set_trace_func(proc)它在線程上建立proc作為處理程序。status它返回線程的狀態(tài)。stop?如果線程正在休眠或已死,則返回true。terminate它終止線程并安排另一個線程運行。thread_variable?(key)如果給定的字符串作為線程局部變量存在,則返回true。thread_variable_get(key)t返回已設(shè)置的線程局部變量的值。thread_variable_set(key, value)將本地線程的鍵設(shè)置為value。thread_variable它返回線程局部變量的數(shù)組。value它使用連接等待線程完成,并返回其值。wakeup使給定線程有資格進行調(diào)度,盡管該線程可能仍在I/O上處于阻塞狀態(tài)。
Ruby - 多線程 - 無涯教程網(wǎng)無涯教程網(wǎng)提供傳統(tǒng)程序只有一個執(zhí)行線程,構(gòu)成該程序的語句或指令將順序執(zhí)行,直到程序終止。多線程...https://www.learnfk.com/ruby/ruby-multithreading.html
柚子快報邀請碼778899分享:無涯教程-Ruby - 多線程
推薦文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。