<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无码精品无码麻豆| 久久不见久久见免费影院www日本| 国产免费爽爽视频免费可以看| 亚洲日本VA中文字幕久久道具| 18禁超污无遮挡无码免费网站国产 | 亚洲国产一区二区视频网站| 国产午夜亚洲精品不卡电影| 国产精品色午夜免费视频| 亚洲jizzjizz少妇| 亚洲欧洲免费视频| 337p欧洲亚洲大胆艺术| 一级毛片免费播放视频| 久久精品亚洲乱码伦伦中文| a级特黄毛片免费观看| 四虎影视免费在线| 亚洲va中文字幕| 又粗又大又猛又爽免费视频 | 涩涩色中文综合亚洲| 一级中文字幕免费乱码专区| 久久久久亚洲AV无码专区网站| 香蕉免费一级视频在线观看| 亚洲综合无码一区二区| 在线永久免费的视频草莓| 亚洲AV日韩AV永久无码绿巨人 | 成年人免费网站在线观看| 亚洲欧美第一成人网站7777| 亚洲人成人无码网www国产| 暖暖日本免费中文字幕| AV在线播放日韩亚洲欧| 18禁亚洲深夜福利人口| 国产亚洲精品免费视频播放 | 久久av免费天堂小草播放| 久久精品国产亚洲AV麻豆王友容| 亚洲一区二区三区免费观看| 亚洲色图在线观看| 午夜成人免费视频|