<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    Ruby Fiber指南(四)迭代器

    Posted on 2010-03-12 12:48 dennis 閱讀(3287) 評論(0)  編輯  收藏 所屬分類: 動態語言my open-source

        Ruby Fiber指南(一)基礎
        Ruby Fiber指南(二)參數傳遞
        Ruby Fiber指南(三)過濾器
        Ruby Fiber指南(四)迭代器
        Ruby Actor指南(五)實現Actor

         上一節介紹了利用Fiber實現類unix管道風格的過濾鏈,這一節將介紹利用Fiber來實現迭代器,我們可以將循環的迭代器看作生產者-消費者模式的特殊的例子。迭代函數產生值給循環體消費。所以可以使用Fiber來實現迭代器。協程的一個關鍵特征是它可以不斷顛倒調用者與被調用者之間的關系,這樣我們毫無顧慮的使用它實現一個迭代器,而不用保存迭代函數返回的狀態,也就是說無需在迭代函數中保存狀態,狀態的保存和恢復交由Fiber自動管理。

         這一節的介紹以一個例子貫穿前后,我們將不斷演化這個例子,直到得到一個比較優雅的可重用的代碼,這個例子就是求數組的全排列。如數組[1,2,3]的全排列包括6種排列:
    2 3 1
    3 2 1
    3 1 2
    1 3 2
    2 1 3
    1 2 3
    全排列的遞歸算法實現很簡單,我們用Ruby實現如下:

    #全排列的遞歸實現
    def permgen (a, n)
        
    if n == 0 then
           printResult(a)
        
    else
            n.times do 
    |i|
               a[n
    -1], a[i] = a[i], a[n-1]
               permgen(a, n 
    - 1)
               a[n
    -1], a[i] = a[i], a[n-1]
           end
        end
    end

    def printResult (a)
        puts a.join(
    " ")
    end

    permgen([
    1,2,3,4],4)
    算法的思路是這樣:
    將數組中的每一個元素放到最后,依次遞歸生成所有剩余元素的排列,沒完成一個排列就打印出來。很顯然,這里有消費者和生產者的關系存在,生產者負責產生排列,消費者負責打印任務,整個程序由消費者驅動,因此用Fiber改寫如下:

    第一步,將打印任務修改為Fiber#yield,生產者產生一個排列后將結果傳遞給消費者并讓出執行權:
    def permgen (a, n)
        
    if n == 0 then
           Fiber.
    yield(a)
        ……
    end

    第二步,實現一個迭代器工廠,返回一個匿名的迭代函數,迭代函數請求Fiber產生一個新的排列:
    def perm(a)
      f
    =Fiber.new do
            permgen(a,a.size)
        end
      
    return lambda{ f.resume if f.alive? }
    end

    這樣一來我們就可以利用一個while循環來打印全排列:
    it=perm([1,2,3,4])

    while a=it.call
       printResult(a)
    end

        注意到,在perm方法中有一個很常見的模式,就是將對Fiber的resume封裝在一個匿名函數內,在lua為了支持這種模式還特意提供了一個coroutine.wrap方法來方便編程,在Ruby Fiber中卻沒有,不過我們可以自己實現下,利用open-class的特性實現起來非常簡單:
    #為Fiber添加wrap方法
    class Fiber
      
    def self.wrap
        
    if block_given?
          f
    =Fiber.new do |*args|
             
    yield *args
          end
          
    return lambda{|*args| f.resume(*args) if f.alive? }
        end
      end
    end
     
        Fiber#wrap方法跟new方法一樣,創建一個新的Fiber,但是返回的是一個匿名函數,這個匿名函數負責去調用fiber的resume,利用wrap改寫perm方法變得更簡潔:
    def perm(a)
      Fiber.wrap{ permgen(a,a.size) }
    end

        但是還不夠,while循環的方式還是不夠優雅,每次都需要明確地調用迭代器的call方法,這一點讓人挺不舒坦,如果能像for...in那樣的泛型循環就好了,我們知道Ruby中的for...in其實是一個語法糖衣,都是轉變成調用集合的each方法并傳入處理的block,因此,要想實現一個優雅的迭代器,我們做下封裝就好了:

    class FiberIterator
      
    def initialize
        @fiber_wrap
    =Fiber.wrap do
            
    yield
        end
      end
      
    def each
        
    while value=@fiber_wrap.call
          
    yield value
        end
      end
    end

    那么現在的perm方法變成了創建一個迭代器FiberIterator:
    def perm(a)
      FiberIterator.new{ permgen(a,a.size) }
    end
    這樣一來我們就可以通過for...in來調用迭代器了

    it=perm([1,2,3,4])
    for a in it
      printResult(a)
    end


       

        
    主站蜘蛛池模板: 色噜噜综合亚洲av中文无码| 日韩视频在线免费观看| 亚洲人成图片小说网站| 免费在线人人电影网| 日本免费网站在线观看| 国产精品无码亚洲一区二区三区| 亚洲AV无码精品色午夜果冻不卡| 国产黄在线播放免费观看| 曰批全过程免费视频在线观看无码 | 性做久久久久免费看| 亚洲精品国产精品| 人妻在线日韩免费视频| 在线精品亚洲一区二区三区| 亚洲国产成人资源在线软件| 欧美亚洲精品一区二区| 久久国产精品成人片免费| 亚洲av成人无码久久精品| 特黄特色大片免费| 99精品热线在线观看免费视频| 亚洲午夜久久影院| 99在线精品免费视频九九视| 亚洲?v女人的天堂在线观看| 亚洲日韩乱码久久久久久| 我的小后妈韩剧在线看免费高清版| 久久久久久亚洲精品不卡| 亚洲色大成网站www永久网站| 久久久久久久久久国产精品免费| 久久亚洲日韩精品一区二区三区| 免费看片在线观看| 亚洲精品成人av在线| 国产情侣激情在线视频免费看| 婷婷综合缴情亚洲狠狠尤物| 国产免费播放一区二区| 亚洲短视频男人的影院| 青青青免费国产在线视频小草| 色欲色欲天天天www亚洲伊| 国产亚洲人成A在线V网站| 99视频免费观看| 亚洲精品无码国产片| 手机在线免费视频| 亚洲免费日韩无码系列|