国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

ディレクトリ 検索
Ruby用戶(hù)指南 3、開(kāi)始 4、簡(jiǎn)單的例子 5、字符串 6、正則表達(dá)式 7、數(shù)組 8、回到那些簡(jiǎn)單的例子 9、流程控制 10、迭代器 11、面向?qū)ο笏季S 12、方法 13、類(lèi) 14、繼承 15、重載方法 16、訪問(wèn)控制 17、單態(tài)方法 18、模塊 19、過(guò)程對(duì)象 20、變量 21、全局變量 22、實(shí)變量 23、局部變量 24、類(lèi)常量 25、異常處理:rescue 26、異常處理:ensure 27、存取器 28、對(duì)象的初始化 29、雜項(xiàng) RGSS入門(mén)教程 1、什么是RGSS 2、開(kāi)始:最簡(jiǎn)單的腳本 3、數(shù)據(jù)類(lèi)型:數(shù)字 4、數(shù)據(jù)類(lèi)型:常量與變量 5、數(shù)據(jù)類(lèi)型:字符串 6、控制語(yǔ)句:條件分歧語(yǔ)句 7、控制語(yǔ)句:循環(huán) 8、函數(shù) 9、對(duì)象與類(lèi) 10、顯示圖片 11、數(shù)組 12、哈希表(關(guān)聯(lián)數(shù)組) 13、類(lèi) 14、數(shù)據(jù)庫(kù) 15、游戲?qū)ο?/a> 16、精靈的管理 17、窗口的管理 18、活動(dòng)指令 19、場(chǎng)景類(lèi) Programming Ruby的翻譯 Programming Ruby: The Pragmatic Programmer's Guide 前言 Roadmap Ruby.new 類(lèi),對(duì)象和變量 容器Containers,塊Blocks和迭代Iterators 標(biāo)準(zhǔn)類(lèi)型 深入方法 表達(dá)式Expressions 異常,捕捉和拋出(已經(jīng)開(kāi)始,by jellen) 模塊 基本輸入輸出 線程和進(jìn)程 當(dāng)遭遇挫折 Ruby和它的世界 Ruby和Web開(kāi)發(fā) Ruby Tk Ruby 和微軟的 Windows 擴(kuò)展Ruby Ruby語(yǔ)言 (by jellen) 類(lèi)和對(duì)象 (by jellen) Ruby安全 反射Reflection 內(nèi)建類(lèi)和方法 標(biāo)準(zhǔn)庫(kù) OO設(shè)計(jì) 網(wǎng)絡(luò)和Web庫(kù) Windows支持 內(nèi)嵌文檔 交互式Ruby Shell 支持 Ruby參考手冊(cè) Ruby首頁(yè) 卷首語(yǔ) Ruby的啟動(dòng) 環(huán)境變量 對(duì)象 類(lèi) 執(zhí)行 結(jié)束時(shí)的相關(guān)處理 線程 安全模型 正則表達(dá)式 字句構(gòu)造 程序 變量和常數(shù) 字面值 操作符表達(dá)式 控制結(jié)構(gòu) 方法調(diào)用 類(lèi)/方法的定義 內(nèi)部函數(shù) 內(nèi)部變量 內(nèi)部常數(shù) 內(nèi)部類(lèi)/模塊/異常類(lèi) 附加庫(kù) Ruby變更記錄 ruby 1.6 特性 ruby 1.7 特性 Ruby術(shù)語(yǔ)集 Ruby的運(yùn)行平臺(tái) pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
テキスト

線程和進(jìn)程



Ruby給了你兩個(gè)基本的方法來(lái)組織你的程序,使它同時(shí)能運(yùn)行自己的不同部分。你可以使用線程在程序內(nèi)部將任務(wù)分割,或者將任務(wù)分解為不同的程序,使用多進(jìn)程來(lái)運(yùn)行。下面我們輪流看一下這兩種方法。

多線程

一般來(lái)說(shuō)在Ruby中同時(shí)做兩件事情最簡(jiǎn)單的是使用Ruby線程。線程在進(jìn)程中,由Ruby解釋器實(shí)現(xiàn)。這使得Ruby線程也能完全的可移至,因?yàn)樗恍枰蕾?lài)特定的操作系統(tǒng),但是這樣你也不能利用本地線程(native threads)的優(yōu)點(diǎn)了。你也許有過(guò)線程饑餓得經(jīng)驗(yàn)(優(yōu)先級(jí)低的線程沒(méi)有機(jī)會(huì)運(yùn)行)。也許你會(huì)遇到線程死鎖,整個(gè)進(jìn)程都被掛起?;蛘咭恍┚€程的某些操作占用了CPU的太多時(shí)間,以至于其它線程不得不等待。但是,不要被這些潛在的問(wèn)題嚇倒,Ruby線程是使你程序并行運(yùn)行的輕量而有效的方法。

創(chuàng)建 Ruby 線程

創(chuàng)建一個(gè)新的線程十分簡(jiǎn)單,下面的部分代碼并行的下載一些網(wǎng)頁(yè),每次有請(qǐng)求調(diào)用,這段代碼都將產(chǎn)生一個(gè)獨(dú)立的線程處理HTTP傳輸。

require?'net/http'
 
pages?=?%w(?www.rubycentral.com   
????????????www.awl.com   
????????????www.pragmaticprogrammer.com   
???????????)
 
threads?=?[]
 
for?page?in?pages   
??threads?<<?Thread.new(page)?{?|myPage|
 
????h?=?Net::HTTP.new(myPage,?80)   
????puts?"Fetching:?#{myPage}"   
????resp,?data?=?h.get('/',?nil?)   
????puts?"Got?#{myPage}:??#{resp.message}"   
??}   
end
 
threads.each?{?|aThread|??aThread.join?}
 

produces:
Fetching:?www.rubycentral.com
Fetching:?www.awl.com
Fetching:?www.pragmaticprogrammer.com
Got?www.rubycentral.com:??OK
Got?www.pragmaticprogrammer.com:??OK
Got?www.awl.com:??OK

讓我們更詳細(xì)的看看這段代碼,這里有一些新技巧在里面。

新線程用 Thread.new 創(chuàng)建,這個(gè)方法接收一個(gè)block作為線程中要運(yùn)行的代碼,在我們的例子里面,這個(gè)block使用net/http庫(kù)從每個(gè)指定的站點(diǎn)抓取首頁(yè),從我們打印出來(lái)的信息來(lái)看,這些抓取活動(dòng)是同時(shí)進(jìn)行的。

當(dāng)我們創(chuàng)建線程的時(shí)候,我們將這個(gè)HTML頁(yè)面作為參數(shù)傳入,這個(gè)參數(shù)然后作為myPage參數(shù)傳給了block。為什么我們這么做而不是直接在block里面用page這個(gè)變量那?

一個(gè)線程共享了所有在它啟動(dòng)之前已經(jīng)存在的所有全局變量,實(shí)例變量和局部變量。善意的人有時(shí)候會(huì)告訴你,共享有時(shí)候不一定是好事。在這個(gè)例子里面,3個(gè)線程將共享page變量,第一個(gè)線程啟動(dòng)之后,page被設(shè)為http://www.rubycentral.com,在這個(gè)時(shí)候,創(chuàng)建線程的循環(huán)還沒(méi)有結(jié)束,第二次,page被設(shè)為http://www.awl.com,如果第一個(gè)線程還沒(méi)有使用page變量運(yùn)行完畢,那么可能這個(gè)線程會(huì)使用page的新值。這個(gè)bug將很難被跟蹤發(fā)現(xiàn)。

但是,在線程塊中創(chuàng)建的局部變量的作用域只在創(chuàng)建它的線程里,而不能被其它線程共享。在我們的例子里面,變量myPage將在線程被創(chuàng)建時(shí)賦值,每個(gè)線程都有自己的myPage變量的拷貝。

 

多線程

另一個(gè)很微妙的地方是程序的最后一行,為什么我們調(diào)用所創(chuàng)每個(gè)建線程的join方法?

當(dāng)一個(gè)Ruby程序結(jié)束退出的時(shí)候,它會(huì)殺死所有的線程,而不管它們的狀態(tài)。但是,你可以通過(guò)線程的 Thread#join 方法,使得主程序在等待這個(gè)線程結(jié)束后再退出。調(diào)用它的線程將會(huì)被阻塞,直到給定的線程結(jié)束。通過(guò)調(diào)用3個(gè)線程的join方法,你可以確定這三個(gè)請(qǐng)求將會(huì)在主程序退出之前完成。

?除了join,還有其它幾個(gè)用于控制線程的方便的方法。首先,你可以用 Thread.current 來(lái)訪問(wèn)當(dāng)前線程,你可以用 Thread.list 來(lái)取得所有線程列表,這個(gè)列表包括所有可運(yùn)行或者已停止的線程。為了檢測(cè)一個(gè)線程的狀態(tài),可以用方法 Thread#statusThread#alive? 。

另外,你可以使用 Thread#priority= 來(lái)設(shè)置線程的不同的優(yōu)先級(jí)別。高優(yōu)先級(jí)的將會(huì)先于低優(yōu)先級(jí)的線程執(zhí)行。

線程變量

在上面我們已經(jīng)說(shuō)過(guò),一個(gè)線程可以訪問(wèn)在它定義之前已經(jīng)存在的,在作用域范圍內(nèi)的變量,但是,在線程內(nèi)部定義的變量的作用域只在這個(gè)線程內(nèi)部有效。

但是,如果你想一個(gè)線程的變量能被其它線程訪問(wèn),包括主線程,該怎么辦呢?Ruby中的線程提供了一個(gè)功能,就是能夠按名字創(chuàng)建和訪問(wèn)線程內(nèi)的局部變量。你可以簡(jiǎn)單的把這個(gè)線程對(duì)象作為一個(gè)哈希,使用[ ]=方法寫(xiě)這個(gè)對(duì)象的變量值,用 [ ]來(lái)讀它的值。在這個(gè)例子里,?每個(gè)線程記錄當(dāng)前變量count的值,把它存到線程的局部變量,名字(key)為mycount。(這里有競(jìng)爭(zhēng)條件的出現(xiàn),但是我們還沒(méi)有談到同步問(wèn)題,這里我們只是忽略它們。)

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)生結(jié)果:
8,?0,?3,?7,?2,?1,?6,?5,?4,?9,?count?=?10

 

主線程等待每個(gè)子線程結(jié)束之后,打印出來(lái)每個(gè)線程得到的count的值。我們?nèi)藶榈淖屆總€(gè)線程在取得count值之前休眠隨機(jī)的時(shí)間,這只是為了增加點(diǎn)趣味而已。

 

線程和異常

 

如果一個(gè)線程拋出一個(gè)沒(méi)有被處理的異常,將會(huì)怎樣呢?這依賴(lài)于系統(tǒng)設(shè)置Thread.abort_on_exception?,這個(gè)設(shè)置在第384頁(yè)和387頁(yè)。

如果abort_on_exception 被設(shè)置為false,這也是默認(rèn)的缺省值,那么如果一個(gè)線程出現(xiàn)錯(cuò)誤而沒(méi)有處理,則這個(gè)線程將會(huì)被殺死,其它沒(méi)有遇到異常的線程將繼續(xù)運(yùn)行。在下面的例子里,編號(hào)為3的線程將產(chǎn)生一個(gè)異常,而不會(huì)輸出任何東西,但是,你仍然可以看到其它線程的輸出。

threads?=?[]
6.times?{?|i|
??threads?<<?Thread.new(i)?{
????raise?"Boom!"?if?i?==?3
????puts?i
??}
}
threads.each?{|t|?t.join?}
產(chǎn)生:
01
2

 
45prog.rb:4:?Boom!?(RuntimeError)         
	from?prog.rb:8:in?`join'         
	from?prog.rb:8         
	from?prog.rb:8:in?`each'         
	from?prog.rb:8
  

 

但是,如果將abort_on_exception 設(shè)為true,一個(gè)線程出現(xiàn)沒(méi)有捕獲(處理)的異常,則所有的線程將都被殺死,上面的例子,如果編號(hào)為3的線程出錯(cuò),所有后面的線程都被殺死,不會(huì)產(chǎn)生任何輸出。

Thread.abort_on_exception?=?true
threads?=?[]
6.times?{?|i|
??threads?<<?Thread.new(i)?{
????raise?"Boom!"?if?i?==?3
????puts?i
??}
}
threads.each?{|t|?t.join?}
produces:
01
2
prog.rb:5:?Boom!?(RuntimeError)
	from?prog.rb:7:in?`initialize'
	from?prog.rb:7:in?`new'
	from?prog.rb:7
	from?prog.rb:3:in?`times'
	from?prog.rb:3

控制線程調(diào)度器

在一個(gè)設(shè)計(jì)良好的應(yīng)用程序中,你應(yīng)該讓線程只做自己改作的事情;在一個(gè)多線程環(huán)境中創(chuàng)建一個(gè)基于時(shí)間的系統(tǒng)一般來(lái)說(shuō)不是一個(gè)好主意。

但是,有時(shí)候我們需要控制線程的運(yùn)行。也許我們的自動(dòng)點(diǎn)唱機(jī)有一個(gè)線程用來(lái)控制指示燈,我們希望在音樂(lè)停止播放的時(shí)候也停止指示燈。你也許在一個(gè)經(jīng)典的生產(chǎn)者-消費(fèi)者關(guān)系中有兩個(gè)線程,一個(gè)消費(fèi)者在生產(chǎn)者掛起的時(shí)候也必須掛起。

類(lèi)Thread 提供了很多方法用來(lái)控制線程調(diào)度,調(diào)用 Thread.stop 能停止當(dāng)前線程,而 Thread#run 將使某個(gè)線程啟動(dòng)運(yùn)行,調(diào)用 Thread.pass 將告訴線程調(diào)度器去執(zhí)行另外一個(gè)線程。? Thread#joinThread#value 將使調(diào)用者掛起,直到這個(gè)線程結(jié)束。

我們可以用下面代碼來(lái)示范一下上面的特點(diǎn)。

t?=?Thread.new?{?sleep?.1;?Thread.pass;?Thread.stop;?}
t.status ? "sleep"
t.run
t.status ? "run"
t.run
t.status ? false

但是,使用這些原始的方法來(lái)控制線程調(diào)度實(shí)現(xiàn)同步,不管怎么說(shuō),都可能會(huì)遇到競(jìng)爭(zhēng)條件。如果你需要在線程中共享數(shù)據(jù),競(jìng)爭(zhēng)條件將會(huì)一直存在并且給調(diào)試帶來(lái)麻煩。幸運(yùn)的是,線程還有另一個(gè)工具:臨界區(qū)(critical section),使用它,我們能編寫(xiě)一個(gè)安全的同步方案。

互斥(Mutual Exclusion)

 

用來(lái)阻塞一個(gè)線程運(yùn)行的低層的方法是使用全局的"線程臨界"(thread critical)條件。當(dāng)這個(gè)條件被設(shè)為true(用 Thread.critical= 方法)時(shí),調(diào)度器將不會(huì)讓任何已經(jīng)存在地線程執(zhí)行,但是,它不會(huì)阻止新線程的建立和運(yùn)行;一些特定的線程操作(比如停止或者殺死一個(gè)線程,在當(dāng)前線程中休眠,或者拋出一個(gè)異常)都會(huì)引起一個(gè)線程被調(diào)度,即使在臨界區(qū)之內(nèi)。

直接使用 Thread.critical= 雖然可行,但是它并不是很方便。幸運(yùn)的是,Ruby自帶了很多其它選項(xiàng),當(dāng)然,最好的兩個(gè)是thread庫(kù)模塊中的類(lèi)Mutex和類(lèi)ConditionVariable。關(guān)于它們的文檔從第457頁(yè)開(kāi)始。

類(lèi) Mutex

Mutex 是一個(gè)為對(duì)互斥地訪問(wèn)某一共享對(duì)象而設(shè)計(jì)的一個(gè)簡(jiǎn)單的信號(hào)量鎖。也就是說(shuō),在一個(gè)時(shí)候,只有一個(gè)線程能持有這個(gè)鎖。其它線程可以繼續(xù)等待直到這個(gè)鎖可用,或者立即返回一個(gè)錯(cuò)誤不再繼續(xù)等待。

一個(gè)mutex經(jīng)常用于原子性的對(duì)一個(gè)共享對(duì)象進(jìn)行修改更新。假設(shè)我們需要更新一個(gè)事務(wù)中的兩個(gè)變量,比如下面的程序模擬增加兩個(gè)數(shù)的計(jì)數(shù)。這個(gè)更新假定是原子性的,外面的世界不可能看到這兩個(gè)數(shù)有不同的值。如果不使用互斥,則不能達(dá)到該目的。

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
Thread.critical?=?1
count1 ? 184846
count2 ? 184846
difference ? 58126

這個(gè)例子顯示了在執(zhí)行的過(guò)程中count1和count2的值曾經(jīng)出現(xiàn)過(guò)不同,盡管最后還是一樣的。

幸運(yùn)的是,我們可以用互斥來(lái)改善這個(gè)例子。

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
count1 ? 21192
count2 ? 21192
difference ? 0

通過(guò)把需要訪問(wèn)共享數(shù)據(jù)的代碼放到muxtex的控制下,我們確保了數(shù)據(jù)的一致性。但不幸的是,你也從這些數(shù)字看到了,我們?cè)诮?jīng)受著性能上的損失。

 

條件變量(Condition Variables)

有時(shí)候使用互斥(mutex )來(lái)保護(hù)對(duì)臨界數(shù)據(jù)的訪問(wèn)并不能滿(mǎn)足要求,比如假設(shè)我們?cè)谝粋€(gè)臨界區(qū)內(nèi),但是你還需要等待一個(gè)特殊的資源,如果你的線程這時(shí)候?yàn)榱说却@個(gè)資源而休眠,可能會(huì)導(dǎo)致其它線程不能釋放這個(gè)資源,因?yàn)樗鼈兌紵o(wú)法進(jìn)入這個(gè)臨界區(qū),原來(lái)的線程一直在鎖定著這個(gè)臨界區(qū)。你也許需要暫時(shí)的放棄對(duì)臨界區(qū)的控制,同時(shí)告訴其它線程你在等待某一資源。當(dāng)這個(gè)資源可用之后,你的線程同時(shí)需要重新得到對(duì)臨界區(qū)的控制權(quán)。

條件變量正是用在此處。一個(gè)條件變量是一個(gè)簡(jiǎn)單的信號(hào)量,它關(guān)聯(lián)一個(gè)特定的資源,在臨界區(qū)的保護(hù)范圍內(nèi)使用。當(dāng)你需要一個(gè)資源而這個(gè)資源暫時(shí)不可用的時(shí)候,你等待一個(gè)條件變量,這個(gè)操作將放棄對(duì)這個(gè)條件變量所在互斥(臨界區(qū)?)的鎖定。當(dāng)其它線程發(fā)送信號(hào)告訴這個(gè)變量可用之后,原來(lái)的線程停止等待立即取得對(duì)臨界區(qū)的鎖定。

 

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
結(jié)果:
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!

另一個(gè)同步機(jī)制的實(shí)現(xiàn),可以參考Ruby發(fā)布程序中l(wèi)ib文件夾下的文件 monitor.rbsync.rb。

 

運(yùn)行多個(gè)進(jìn)程(Multiple Processes)

有時(shí)候你可能需要把一個(gè)任務(wù)分成幾個(gè)進(jìn)程級(jí)別的子任務(wù),或者你需要運(yùn)行一個(gè)另外的不使用Ruby寫(xiě)的程序,沒(méi)關(guān)系,Ruby有好幾種方法能使你創(chuàng)建和管理其它獨(dú)立的進(jìn)程。

 

產(chǎn)生一個(gè)新的進(jìn)程

在Ruby中產(chǎn)生一個(gè)新的進(jìn)程有好幾種方法,最簡(jiǎn)單的方法是運(yùn)行一個(gè)命令并且等到它結(jié)束。你也許運(yùn)行一些其它的獨(dú)立的命令,并且從主機(jī)得到返回的結(jié)果,Ruby提供了system方法和反引號(hào)方法。(反引號(hào)即"`")

 system("tar?xzf?test.tgz")  ?   tar:?test.tgz:?Cannot?open:?No?such?file?or?directory\ntar:
?Error?is?not?recoverable:?exiting?now\ntar:?Child?returned?status?2\ntar:
?Error?exit?delayed?from?previous?errors\nfalse
result?=?`date`     
result   ?  "Sun?Jun??9?00:08:50?CDT?2002\n"

方法 Kernel::system 運(yùn)行一個(gè)指定的命令,如果這個(gè)命令存在且正確的運(yùn)行結(jié)束,這個(gè)方法返回true,否則返回false。如果這個(gè)命令運(yùn)行失敗,你可以從全局變量$?得到這個(gè)命令的返回代碼。

但system也有一個(gè)問(wèn)題,就是它所運(yùn)行程序的輸出簡(jiǎn)單的被指定到了你的程序的輸出,這可能不是你想要的。為了取得子進(jìn)程的標(biāo)準(zhǔn)輸出,你可以用反引號(hào),比如上面例子的 `date` 。注意,你需要用 String#chomp 來(lái)去除返回結(jié)果最后的換行符。

這中方法對(duì)簡(jiǎn)單的場(chǎng)合比較合適,我們只需要運(yùn)行一個(gè)命令,然后取得它的返回結(jié)果。但是,很多時(shí)候我們都需要對(duì)進(jìn)程有更多的控制,比如我們需要和子進(jìn)程進(jìn)行會(huì)話,向它輸入數(shù)據(jù),并且從它取回?cái)?shù)據(jù)。方法 IO.popen 正是具有這樣的作用。popen方法以一個(gè)子進(jìn)程來(lái)運(yùn)行一個(gè)命令,并且把這個(gè)進(jìn)程的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出綁定到Ruby的IO對(duì)象。向IO對(duì)象寫(xiě)數(shù)據(jù),子進(jìn)程就可以從它的標(biāo)準(zhǔn)輸入讀取數(shù)據(jù),而子進(jìn)程輸出的數(shù)據(jù),也可以通過(guò)Ruby的IO對(duì)象讀出來(lái)。

比如,我們的操作系統(tǒng)中有一個(gè)有用的程序叫做pig,這個(gè)程序從標(biāo)準(zhǔn)輸入讀入數(shù)據(jù),然后以pig Latin方式打印這些數(shù)據(jù)。

pig?=?IO.popen("pig",?"w+")
pig.puts?"ice?cream?after?they?go?to?bed"
pig.close_write
puts?pig.gets
produces:
iceway?eamcray?afterway?eythay?ogay?otay?edbay

這個(gè)例子看起來(lái)很簡(jiǎn)單,打開(kāi)這個(gè)管道(pipe),寫(xiě)入一個(gè)短語(yǔ),然后讀取返回結(jié)果。但是pig程序并不會(huì)立即將它寫(xiě)的東西flush。假如上面例子中,如果pig.puts 后面緊跟pig.gets的話,程序?qū)⒈粧炱?,pig程序處理了我們的輸入,但是返回結(jié)果卻一直不會(huì)被寫(xiě)到管道。我們必須在這兩行之間插入 pig.close_write ,這將給pig的標(biāo)準(zhǔn)輸入發(fā)送一個(gè)文件結(jié)束標(biāo)志(end-of-file),然后我們需要的結(jié)果就會(huì)返回。

popen方法還有另外一些注意事項(xiàng)。如果指定的命令是一個(gè)減號(hào)("-"),Ruby將強(qiáng)迫產(chǎn)生一個(gè)新的Ruby解釋器,它將和原來(lái)的解釋器一起運(yùn)行。原來(lái)的解釋器進(jìn)程將得到一個(gè)IO對(duì)象作為返回結(jié)果,而子解釋器將得到nil。

pipe?=?IO.popen("-","w+")
if?pipe
??pipe.puts?"Get?a?job!"
??$stderr.puts?"Child?says?'#{pipe.gets.chomp}'"
else
??$stderr.puts?"Dad?says?'#{gets.chomp}'"
??puts?"OK"
end
produces:
Dad?says?'Get?a?job!'
Child?says?'OK'

除了popen方法,傳統(tǒng)的Unix調(diào)用 Kernel::forkIO.pipeKernel::exec 也可以在支持它們的系統(tǒng)上使用。許多IO方法和 Kernel::open 也能產(chǎn)生新的子進(jìn)程,使用方法是將文件名前面加上一個(gè)豎線``|'' 。注意你不能用 File.new 來(lái)產(chǎn)生一個(gè)子進(jìn)程,這個(gè)方法只是用于文件。

Independent Children

有時(shí)候我們并不需要這樣處理:我們只想把產(chǎn)生的子進(jìn)程賦給一個(gè)變量,然后繼續(xù)處理自己的事務(wù)。一段時(shí)間以后,我們也許還需要一下這個(gè)進(jìn)程是否結(jié)束。比如,我們需要從主程序分離一個(gè)需要很長(zhǎng)運(yùn)行時(shí)間的外部排序:

exec("sort?testfile?>?output.txt")?if?fork?==?nil
#?The?sort?is?now?running?in?a?child?process
#?carry?on?processing?in?the?main?program

 
#?then?wait?for?the?sort?to?finish                
Process.wait
  

系統(tǒng)調(diào)用 Kernel::fork 在父進(jìn)程中返回fork產(chǎn)生的子進(jìn)程id,在子進(jìn)程中返回nil,所以,上面例子中子進(jìn)程將調(diào)用 Kernel::exec 來(lái)運(yùn)行一個(gè)外部的排序。一段時(shí)間以后,我們使用 Process::wait ,這將等待排序完成,然后返回這個(gè)進(jìn)程的id。(pid)

如果你需要在子進(jìn)程退出后通知父進(jìn)程(而不是等待子進(jìn)程結(jié)束),可以用 Kernel::trap 來(lái)對(duì)返回的信號(hào)進(jìn)行處理。比如這里我們建立了一個(gè)用于捕獲SIGCLD信號(hào)的trap,這個(gè)信號(hào)的意思是“子進(jìn)程結(jié)束(死亡)”

trap("CLD")?{
??pid?=?Process.wait
??puts?"Child?pid?#{pid}:?terminated"
??exit
}

 
exec("sort?testfile?>?output.txt")?if?fork?==?nil
 
#?do?other?stuff...
 
produces:
Child?pid?31842:?terminated

塊(Block)和子進(jìn)程

IO.popen 也能像 File.open 那樣接受一個(gè)block。通過(guò)傳遞一個(gè)參數(shù)給 popen 作為一個(gè)命令,比如 date,然后,這個(gè)block將得到一個(gè)IO對(duì)象作為參數(shù)。

IO.popen?("date")?{?|f|?puts?"Date?is?#{f.gets}"?}
produces:
Date?is?Sun?Jun??9?00:08:50?CDT?2002

這個(gè)IO對(duì)象將會(huì)在BLOCK結(jié)束之后自動(dòng)關(guān)閉,就如同 File.open 一樣。

如果你給 Kernel::fork 提供一個(gè)block,那么這些block中的代碼將在Ruby的子進(jìn)程中運(yùn)行,而父進(jìn)程在block結(jié)束后繼續(xù)運(yùn)行。

fork?do
??puts?"In?child,?pid?=?#$$"
??exit?99
end
pid?=?Process.wait
puts?"Child?terminated,?pid?=?#{pid},?exit?code?=?#{$??>>?8}"
produces:
In?child,?pid?=?31849
Child?terminated,?pid?=?31849,?exit?code?=?99

最后一個(gè)問(wèn)題,為什么我們子進(jìn)程的返回代碼 $? 要右移8位?這是Posix系統(tǒng)的特點(diǎn),退出代碼(exit code)的低8位是程序結(jié)束的原因,高8位才是真正的退出代碼。


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright ? 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).

Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.

Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
前の記事: 次の記事: