2013-05-20 26 views
8

我不明白是怎麼如下:Ruby中的Fibers有什麼意義?

counts = Hash.new(0) 

File.foreach("testfile") do |line| 
    line.scan(/\w+/) do |word| 
    word = word.downcase 
    counts[word] += 1 
    end 
end 

counts.keys.sort.each {|k| print "#{k}:#{counts[k]} "} 

比差那麼多:

words = Fiber.new do 
    File.foreach("testfile") do |line| 
    line.scan(/\w+/) do |word| 
     Fiber.yield word.downcase 
    end 
    end 
end 

counts = Hash.new(0) 

while word = words.resume 
    counts[word] += 1 
end 

counts.keys.sort.each {|k| print "#{k}:#{counts[k]} "} 

回答

24

纖維是暫停和恢復的任意代碼塊的方式。像這樣的例子並不是一個很好的用例,因爲它沒有提供任何比傳統閱讀和處理方式更有利的優勢。

在這個特殊的例子,如果你想變得更好,你會寫一個枚舉風格的界面,所以你可以寫:

words = WordsReader.new("testfile") 

words.each do |word| 
    # ... 
end 

凡纖維成爲重要的是在編寫異步代碼。例如,在EventMachine環境中,您需要能夠發出異步調用,暫停代碼塊並在收到響應時恢復它。

這結束這樣看:

async_call(argument1, argument2) do |response_1| 
    if (response_1.ok?) 
    async_call(argument3, argument4) do |response_2| 
     if (response_2.ok?) 
     async_call(argument5, argument6) do |response_3| 
      if (response_3.ok?) 
      do_something(response_1, response_2, response_3) 
      else 
      panic_and_fail! 
      end 
     end 
     else 
     panic_and_fail! 
     end 
    end 
    else 
    panic_and_fail! 
    end 
end 

這種類型的嵌套,嵌套和再嵌套調用結構的籠統稱作「回調地獄」,因爲它變得非常難以管理,一旦你的邏輯變得非不重要的。一種扁平化這種結構的方法是使用纖維。一個正確的光纖化等價物是:

begin 
    response_1 = fiber_call(argument1, argument2) 
    response_2 = fiber_call(argument3, argument4) 
    response_3 = fiber_call(argument5, argument6) 

    do_something(response_1, response_2, response_3) 

rescue NotOkay 
    panic_and_fail! 
end 

光纖可以利用異常,其中回調類型的代碼不能。如果有效使用,例外可以大量簡化代碼塊,如您在此處所見。而不是在每個響應上測試ok?,而是預計該調用會拋出NotOkay類型的異常。

回調不能可靠地拋出異常,因爲在回調發生時,調用的發起者已經超出範圍。這是使用回調進行異步編程的一個基本限制。光纖驅動的代碼維護一個適當的調用棧,它只是暫停和恢復,所以異常通過調用者正確地級聯。

我發現纖維既易於理解又非常難以正確應用。大多數情況下你不需要直接使用它們,你將使用一個庫來代替它們。編寫「光纖感知」代碼與編寫「線程安全」代碼不同。正確的做法可能會非常棘手。

+4

你在17分鐘內寫完了所有內容? –

+3

顯然如此。不知道我正在計時! – tadman

+2

Wow Tadman,我真的很感謝你爲了向我和任何可能遇到它的人解釋這個深度。對此,我真的非常感激。你好,加拿大同胞! :) – Senjai