<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-11 23:49 dennis 閱讀(4533) 評論(1)  編輯  收藏 所屬分類: 動態語言my open-source

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

         在學習了Fiber的基礎知識之后,可以嘗試用Fiber去做一些比較有趣的事情。這一節將講述如何使用Fiber來實現類似unix系統中的管道功能。在unix系統中,可以通過管道將多個命令組合起來做一些強大的功能,最常用的例如查找所有的java進程:
    ps aux|grep java
    通過組合ps和grep命令來實現,ps的輸出作為grep的輸入,如果有更多的命令就形成了一條過濾鏈。過濾器本質上還是生產者和消費者模型,前一個過濾器產生結果,后一個過濾器消費這個結果并產生新的結果給下一個過濾器消費。因此我們就從最簡單的生產者消費者模型實現說起。
    我們要展示的這個例子場景是這樣:生產者從標準輸入讀入用戶輸入并發送給消費者,消費者打印這個輸入,整個程序是由消費者驅動的,消費者喚醒生存者去讀用戶輸入,生產者讀到輸入后讓出執行權給消費者去打印,整個過程通過生產者和消費者的協作完成。
    生產者發送是通過yield返回用戶輸入給消費者(還記的上一節嗎?):

    def send(x)
      Fiber.
    yield(x)
    end

    而消費者的接收則是通過喚醒生產者去生產:
    def receive(prod)
      prod.resume
    end

    生產者是一個Fiber,它的任務就是等待用戶輸入并發送結果給消費者:
    def producer()
      Fiber.new do
        
    while true
          x
    =readline.chomp
          send(x)
        end
      end
    end

    消費者負責驅動生產者,并且在接收到結果的時候打印,消費者是root fiber:
    def consumer(producer)
      
    while true
        x
    =receive(producer)
        
    break if x=='quit'
        puts x
      end
    end

        最終的調用如下:
    consumer(producer())
       完整的程序如下:

    #生產者消費者
    require 'fiber'

    def send(x)
      Fiber.
    yield(x)
    end

    def receive(prod)
      prod.resume
    end

    def producer()
      Fiber.new do
        
    while true
          x
    =readline.chomp
          send(x)
        end
      end
    end


    def consumer(producer)
      
    while true
        x
    =receive(producer)
        
    break if x=='quit'
        puts x
      end
    end
    if $0==__FILE__
      consumer(producer())
    end

       讀者可以嘗試在ruby1.9下運行這個程序,每次程序都由消費者驅動生產者去等待用戶輸入,用戶輸入任何東西之后回車,生產者開始運行并將讀到的結果發送給消費者并讓出執行權(通過yield),消費者在接收到yield返回的結果后打印這個結果,因此整個交互過程是一個echo的例子。

    最終的調用consumer(producer())已經有過濾器的影子在了,如果我們希望在producer和consumer之間插入其他過程對用戶的輸入做處理,也就是安插過濾器,那么新的過濾器也將作為fiber存在,新的fiber消費producer的輸出,并輸出新的結果給消費者,例如我們希望將用戶的輸入結果加上行號再打印,那么就插入一個稱為filter的fiber:
    def filter(prod)
      
    return Fiber.new do
        line
    =1
        
    while true
          value
    =receive(prod)
          value
    =sprintf("%5d %s",line,value)
          send(value)
          line
    =line.succ
        end
      end
    end

        最終組合的調用如下:
     consumer(filter(producer()))
       類似unix系統那樣,簡單的加入新的fiber組合起來就可以為打印結果添加行號。

    類似consumer(filter(producer()))的調用方式盡管已經很直觀,但是我們還是希望能像unix系統那樣調用,也就是通過豎線作為管道操作符:
    producer | filter | consumer
    這樣的調用方式更將透明直觀,清楚地表明整個過濾器鏈的運行過程。幸運的是在Ruby中支持對|方法符的重載,因此要實現這樣的操作符并非難事,只要對Fiber做一層封裝即可,下面給出的代碼來自《Programming ruby》的作者Dave Thomas的blog

    class PipelineElement
       attr_accessor :source
       
    def initialize
          @fiber_delegate 
    = Fiber.new do
             process
          end
       end

       
    def |(other)
          other.source 
    = self
          other
       end

       
    def resume
          @fiber_delegate.resume
       end

       
    def process
          
    while value = input
             handle_value(value)
          end
       end

       
    def handle_value(value)
          output(value)
       end

       
    def input
          @source.resume
       end

       
    def output(value)
          Fiber.
    yield(value)
       end
    end

    這段代碼非常巧妙,將Fiber和Ruby的功能展示的淋漓盡致。大致解說下,PipelineElement作為任何一個過濾器的父類,其中封裝了一個fiber,這個fiber默認執行process,在process方法中可以看到上面生產者和消費者例子的影子,input類似receive方法調用前置過濾器(source),output則將本過濾器處理的結果作為參數傳遞給yield并讓出執行權,讓這個過濾器的調用者(也就是后續過濾器)得到結果并繼續處理。PipelineElement實現了“|”方法,用于組合過濾器,將下一個過濾器的前置過濾器設置為本過濾器,并返回下一個過濾器。整個過濾鏈的驅動者是最后一個過濾器。

    有了這個封裝,那么上面生產者消費者的例子可以改寫為:
    class Producer < PipelineElement
       
    def process
         
    while true
           value
    =readline.chomp
           handle_value(value)
         end
       end
    end

    class Filter < PipelineElement
      
    def initialize
        @line
    =1
        super()
      end
      
    def handle_value(value)
        value
    =sprintf("%5d %s",@line,value)
        output(value)
        @line
    =@line.succ
      end
    end

    class Consumer < PipelineElement
      
    def handle_value(value)
        puts value
      end
    end

       現在的調用方式可以跟unix的管道很像了:
    producer=Producer.new
    filter
    =Filter.new
    consumer
    =Consumer.new

    pipeline 
    = producer | filter | consumer
    pipeline.resume
    如果你打印pipeline對象,你將看到一條清晰的過濾鏈,
    #<Consumer:0x8f08bf4 @fiber_delegate=#<Fiber:0x8f08a88>, @source=#<Filter:0x8f08db4 @line=1, @fiber_delegate=#<Fiber:0x8f08d60>, @source=#<Producer:0x8f09054 @fiber_delegate=#<Fiber:0x8f09038>>>>



    評論

    # re: Ruby Fiber指南(三)過濾器[未登錄]  回復  更多評論   

    2010-03-15 12:21 by Zale-U
    參考了!
    主站蜘蛛池模板: 精品成在人线AV无码免费看 | 美女一级毛片免费观看| 国产成人亚洲精品无码AV大片| 国产VA免费精品高清在线| 97久久免费视频| 国产精品嫩草影院免费| 国产亚洲精品va在线| 亚洲剧场午夜在线观看| 全部在线播放免费毛片| 91香焦国产线观看看免费| 91亚洲一区二区在线观看不卡| 色偷偷噜噜噜亚洲男人| 69视频免费观看l| 91嫩草亚洲精品| 女人18毛片特级一级免费视频| 亚洲精品无码国产| 久久99精品视免费看| 亚洲福利精品一区二区三区| 亚洲电影在线免费观看| 最近的2019免费中文字幕| 日本免费一区二区三区最新| 亚洲精品视频免费看| 我要看免费的毛片| 亚洲精品午夜在线观看| 97在线线免费观看视频在线观看| 久久精品国产亚洲Aⅴ香蕉| 欧洲亚洲国产精华液| 亚洲中文字幕在线观看| a毛片成人免费全部播放| 亚洲高清视频在线观看| aa级毛片毛片免费观看久| 亚洲日本一区二区三区在线不卡| 自拍偷自拍亚洲精品播放| 日韩成人免费在线| 成人片黄网站色大片免费观看cn | 四虎影视在线看免费观看| 在线观看免费精品国产| a一级毛片免费高清在线| 91亚洲精品麻豆| 亚洲综合无码精品一区二区三区| 97人妻无码一区二区精品免费|