每一個正在系統上運行的程序都是一個進程。每一個進程包含一到多個線程。html
線程是程序中一個單一的順序控制流程,在單個程序中同時運行多個線程完成不一樣的工做,稱爲多線程。npm
Ruby 中咱們能夠經過 Thread 類來建立多線程,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}"
以上代碼執行結果爲:ruby
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
一、線程的建立可使用Thread.new,一樣能夠以一樣的語法使用Thread.start 或者Thread.fork這三個方法來建立線程。服務器
二、建立線程後無需啓動,線程會自動執行。網絡
三、Thread 類定義了一些方法來操控線程。線程執行Thread.new中的代碼塊。多線程
四、線程代碼塊中最後一個語句是線程的值,能夠經過線程的方法來調用,若是線程執行完畢,則返回線程值,不然不返回值直到線程執行完畢。ide
五、Thread.current 方法返回表示當前線程的對象。 Thread.main 方法返回主線程。
六、經過 Thread.Join 方法來執行線程,這個方法會掛起主線程,直到當前線程執行完畢。
線程有5種狀態:
線程狀態 | 返回值 |
---|---|
Runnable | run |
Sleeping | Sleeping |
Aborting | aborting |
Terminated normally | false |
Terminated with exception | nil |
當某線程發生異常,且沒有被rescue捕捉到時,該線程一般會被無警告地終止。可是,如有其它線程由於Thread#join的關係一直等待該線程的話,則等待的線程一樣會被引起相同的異常。
begin t = Thread.new do Thread.pass # 主線程確實在等join raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end
使用下列3個方法,就可讓解釋器在某個線程因異常而終止時中斷運行。
Thread.abort_on_exception
設置標誌。Thread#abort_on_exception
對指定的線程設定標誌。當使用上述3種方法之一後,整個解釋器就會被中斷。
t = Thread.new { ... } t.abort_on_exception = true
在Ruby中,提供三種實現同步的方式,分別是:
1. 經過Mutex類實現線程同步
2. 監管數據交接的Queue類實現線程同步
3. 使用ConditionVariable實現同步控制
經過Mutex類實現線程同步控制,若是在多個線程鍾同時須要一個程序變量,能夠將這個變量部分使用lock鎖定。 代碼以下:
#encoding:gbk 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
除了使用lock鎖定變量,還可使用try_lock鎖定變量,還可使用Mutex.synchronize同步對某一個變量的訪問。
Queue類就是表示一個支持線程的隊列,可以同步對隊列末尾進行訪問。不一樣的線程可使用統一個對類,可是不用擔憂這個隊列中的數據是否可以同步,另外使用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
線程能夠有其私有變量,線程的私有變量在線程建立的時候寫入線程。能夠被線程範圍內使用,可是不能被線程外部進行共享。
可是有時候,線程的局部變量須要別別的線程或者主線程訪問怎麼辦?ruby當中提供了容許經過名字來建立線程變量,相似的把線程看作hash式的散列表。經過[]=寫入並經過[]讀出數據。咱們來看一下下面的代碼:
#!/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 能夠訪問本身做用域內的全部數據,但若是有須要在某個線程內訪問其餘線程的數據應該怎麼作呢? Thread 類提供了線程數據互相訪問的方法,你能夠簡單的把一個線程做爲一個 Hash 表,能夠在任何線程內使用 []= 寫入數據,使用 [] 讀出數據。
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"]}" }
能夠看到,把線程做爲一個 Hash 表,使用 [] 和 []= 方法,咱們實現了線程之間的數據共享。
Mutex(Mutal Exclusion = 互斥鎖)是一種用於多線程編程中,防止兩條線程同時對同一公共資源(好比全局變量)進行讀寫的機制。
#!/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
#!/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又必須使用顯示器,這樣就造成了死鎖。
當咱們在使用 Mutex 對象時須要注意線程死鎖。
#!/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 若其值爲真的話,一旦某線程因異常而終止時,整個解釋器就會被中斷。它的默認值是假,也就是說,在一般狀況下,若某線程發生異常且該異常未被Thread#join等檢測到時,該線程會被無警告地終止。 |
2 | Thread.abort_on_exception= 若是設置爲 true, 一旦某線程因異常而終止時,整個解釋器就會被中斷。返回新的狀態 |
3 | Thread.critical 返回布爾值。 |
4 | Thread.critical= 當其值爲true時,將不會進行線程切換。若當前線程掛起(stop)或有信號(signal)干預時,其值將自動變爲false。 |
5 | Thread.current 返回當前運行中的線程(當前線程)。 |
6 | Thread.exit 終止當前線程的運行。返回當前線程。若當前線程是惟一的一個線程時,將使用exit(0)來終止它的運行。 |
7 | Thread.fork { block } 與 Thread.new 同樣生成線程。 |
8 | Thread.kill( aThread ) 終止線程的運行. |
9 | Thread.list 返回處於運行狀態或掛起狀態的活線程的數組。 |
10 | Thread.main 返回主線程。 |
11 | Thread.new( [ arg ]* ) {| args | block } 生成線程,並開始執行。數會被原封不動地傳遞給塊. 這就能夠在啓動線程的同時,將值傳遞給該線程所固有的局部變量。 |
12 | Thread.pass 將運行權交給其餘線程. 它不會改變運行中的線程的狀態,而是將控制權交給其餘可運行的線程(顯式的線程調度)。 |
13 | Thread.start( [ args ]* ) {| args | block } 生成線程,並開始執行。數會被原封不動地傳遞給塊. 這就能夠在啓動線程的同時,將值傳遞給該線程所固有的局部變量。 |
14 | Thread.stop 將當前線程掛起,直到其餘線程使用run方法再次喚醒該線程。 |
如下實例調用了線程實例化方法 join:
#!/usr/bin/ruby thr = Thread.new do # 實例化 puts "In second thread" raise "Raise exception" end thr.join # 調用實例化方法 join
如下是完整實例化方法列表:
序號 | 方法描述 |
---|---|
1 | thr[ name ] 取出線程內與name相對應的固有數據。 name能夠是字符串或符號。 若沒有與name相對應的數據時, 返回nil。 |
2 | thr[ name ] = 設置線程內name相對應的固有數據的值, name能夠是字符串或符號。 若設爲nil時, 將刪除該線程內對應數據。 |
3 | thr.abort_on_exception 返回布爾值。 |
4 | thr.abort_on_exception= 若其值爲true的話,一旦某線程因異常而終止時,整個解釋器就會被中斷。 |
5 | thr.alive? 若線程是"活"的,就返回true。 |
6 | thr.exit 終止線程的運行。返回self。 |
7 | thr.join 掛起當前線程,直到self線程終止運行爲止. 若self因異常而終止時, 將會當前線程引起一樣的異常。 |
8 | thr.key? 若與name相對應的線程固有數據已經被定義的話,就返回true |
9 | thr.kill 相似於 Thread.exit 。 |
10 | thr.priority 返回線程的優先度. 優先度的默認值爲0. 該值越大則優先度越高. |
11 | thr.priority= 設定線程的優先度. 也能夠將其設定爲負數. |
12 | thr.raise( anException ) 在該線程內強行引起異常. |
13 | thr.run 從新啓動被掛起(stop)的線程. 與wakeup不一樣的是,它將當即進行線程的切換. 若對死進程使用該方法時, 將引起ThreadError異常. |
14 | thr.safe_level 返回self 的安全等級. 當前線程的safe_level與$SAFE相同. |
15 | thr.status 使用字符串"run"、"sleep"或"aborting" 來表示活線程的狀態. 若某線程是正常終止的話,就返回false. 若因異常而終止的話,就返回nil。 |
16 | thr.stop? 若線程處於終止狀態(dead)或被掛起(stop)時,返回true. |
17 | thr.value 一直等到self線程終止運行(等同於join)後,返回該線程的塊的返回值. 若在線程的運行過程當中發生了異常, 就會再次引起該異常. |
18 | thr.wakeup 把被掛起(stop)的線程的狀態改成可執行狀態(run), 若對死線程執行該方法時,將會引起ThreadError異常。 |
RubyGems 是 Ruby 的一個包管理器,它提供一個分發 Ruby 程序和庫的標準格式,還提供一個管理程序包安裝的工具。
RubyGems 旨在方便地管理 gem 安裝的工具,以及用於分發 gem 的服務器。這相似於 Ubuntu 下的apt-get, Centos 的 yum,Python 的 pip。
RubyGems大約建立於2003年11月,從Ruby 1.9版起成爲Ruby標準庫的一部分。
若是你的 Ruby 低於 1.9 版本,也能夠經過手動安裝:
更新 RubyGems 命令:
$ gem update --system # 須要管理員或root用戶
Gem 是 Ruby 模塊 (叫作 Gems) 的包管理器。其包含包信息,以及用於安裝的文件。
Gem一般是依照".gemspec"文件構建的,包含了有關Gem信息的YAML文件。Ruby代碼也能夠直接創建Gem,這種狀況下一般利用Rake來進行。
gem命令用於構建、上傳、下載以及安裝Gem包。
RubyGems 在功能上與 apt-get、portage、yum 和 npm 很是類似。
安裝:
gem install mygem
卸載:
gem uninstall mygem
列出已安裝的gem:
gem list --local
列出可用的gem,例如:
gem list --remote
爲全部的gems建立RDoc文檔:
gem rdoc --all
下載一個gem,但不安裝:
gem fetch mygem
從可用的gem中搜索,例如:
gem search STRING --remote
gem命令也被用來構建和維護.gemspec和.gem文件。
利用.gemspec文件構建.gem:
gem build mygem.gemspec
因爲國內網絡緣由(你懂的),致使 rubygems.org 存放在 Amazon S3 上面的資源文件間歇性鏈接失敗。
因此你會與遇到 gem install rack 或 bundle install 的時候半天沒有響應,具體能夠用 gem install rails -V 來查看執行過程。
所以咱們能夠將它修改成淘寶下載源: http://ruby.taobao.org/首先,查看當前源:
$ gem sources -l *** CURRENT SOURCES *** https://rubygems.org/
接着,移除https://rubygems.org/,並添加淘寶下載源 http://ruby.taobao.org/。
$ gem sources --remove https://rubygems.org/ $ gem sources -a https://ruby.taobao.org/ $ gem sources -l *** CURRENT SOURCES *** https://ruby.taobao.org # 請確保只有 ruby.taobao.org $ gem install rails
你能夠用bundle的gem源代碼鏡像命令。
$ bundle config mirror.https://rubygems.org https://ruby.taobao.org
這樣你不用改你的 Gemfile 的 source。
source 'https://rubygems.org/' gem 'rails', '4.1.0' ...