Ruby Fiber指南(三)过滤器
Ruby Fiber指南(二)参数传递
Ruby Fiber指南(三)过滤器
Ruby Fiber指南(四)迭代器
Ruby Actor指南(五)实现Actor
在学习了Fiber的基础知识之后,可以尝试用Fiber去做一些比较有趣的事情。这一节将讲述如何使用Fiber来实现类似unix系统中的管道功能。在unix系统中,可以通过管道将多个命令组合起来做一些强大的功能,最常用的例如查找所有的java进程:
通过组合ps和grep命令来实现,ps的输出作为grep的输入,如果有更多的命令就形成了一条过滤链。过滤器本质上还是生产者和消费者模型,前一个过滤器产生结果,后一个过滤器消费这个结果并产生新的结果给下一个过滤器消费。因此我们就从最简单的生产者消费者模型实现说起。
我们要展示的这个例子场景是这样:生产者从标准输入读入用户输入并发送给消费者,消费者打印这个输入,整个程序是由消费者驱动的,消费者唤醒生存者去读用户输入,生产者读到输入后让出执行权给消费者去打印,整个过程通过生产者和消费者的协作完成。
生产者发送是通过yield返回用户输入给消费者(还记的上一节吗?):
def send(x)
Fiber.yield(x)
end
而消费者的接收则是通过唤醒生产者去生产:
prod.resume
end
生产者是一个Fiber,它的任务就是等待用户输入并发送结果给消费者:
Fiber.new do
while true
x=readline.chomp
send(x)
end
end
end
消费者负责驱动生产者,并且在接收到结果的时候打印,消费者是root fiber:
while true
x=receive(producer)
break if x=='quit'
puts x
end
end
最终的调用如下:
完整的程序如下:
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:
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
最终组合的调用如下:
类似unix系统那样,简单的加入新的fiber组合起来就可以为打印结果添加行号。
类似consumer(filter(producer()))的调用方式尽管已经很直观,但是我们还是希望能像unix系统那样调用,也就是通过竖线作为管道操作符:
这样的调用方式更将透明直观,清楚地表明整个过滤器链的运行过程。幸运的是在Ruby中支持对|方法符的重载,因此要实现这样的操作符并非难事,只要对Fiber做一层封装即可,下面给出的代码来自《Programming ruby》的作者Dave Thomas的blog:
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实现了“|”方法,用于组合过滤器,将下一个过滤器的前置过滤器设置为本过滤器,并返回下一个过滤器。整个过滤链的驱动者是最后一个过滤器。
有了这个封装,那么上面生产者消费者的例子可以改写为:
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的管道很像了:
filter=Filter.new
consumer=Consumer.new
pipeline = producer | filter | consumer
pipeline.resume
如果你打印pipeline对象,你将看到一条清晰的过滤链,
Ruby Fiber指南(三)过滤器相关推荐
- Linux文件命令精通指南(三)(转)
Linux文件命令精通指南(三)(转) 查看和查找文件 文件过滤器 用来读取文件内容和在文件内容上执行操作的命令有时被称为 1y滤器.sed 和 awk 命令是两个滤波器的例子,因为在以前的 OTN ...
- C++11 并发指南三(Lock 详解)
在 <C++11 并发指南三(std::mutex 详解)>一文中我们主要介绍了 C++11 标准中的互斥量(Mutex),并简单介绍了一下两种锁类型.本节将详细介绍一下 C++11 标准 ...
- C++11 并发指南三(Lock 详解)(转载)
multithreading 多线程 C++11 C++11多线程基本使用 C++11 并发指南三(Lock 详解) 在 <C++11 并发指南三(std::mutex 详解)>一文中我们 ...
- [ISUX译]iOS 9人机界面指南(三):iOS 技术
[ISUX译]iOS 9人机界面指南(三):iOS 技术 UI规范 summer 2015-11-29 3247浏览 0评论 专为0基础小白量身打造的UI设计入门课程(ps,ai软件+图标技巧),在线 ...
- 端粒效应《The Telemere Effect》程序员的养生指南(三)身心与生活
身为程序员,面临着久坐,工作时间长,工作量大等种种问题.健康显得至关重要.接下来,打算借助一本诺奖得主写的书,来探讨下怎么能够更加健康的做好程序员的工作.端粒效应<The Telomere Ef ...
- C++11 并发指南三(std::mutex 详解)
上一篇<C++11 并发指南二(std::thread 详解)>中主要讲到了 std::thread 的一些用法,并给出了两个小例子,本文将介绍 std::mutex 的用法. Mutex ...
- eBPF 入门开发实践指南三:在 eBPF 中使用 fentry 监测捕获 unlink 系统调用
eBPF (Extended Berkeley Packet Filter) 是 Linux 内核上的一个强大的网络和性能分析工具.它允许开发者在内核运行时动态加载.更新和运行用户定义的代码. 本文是 ...
- 新晋总监生存指南三——OKR实践
一.什么是OKR 书接上文:新晋总监生存指南二--建立指标 OKR在我们团队正循环大图中占有很重的分量,好的OKR实践同时也是上文中数据指标实践的案例.反向论述可以认为,数据指标建设混乱的团队很难运用 ...
- ASP.NET 系列_07_编程指南(三)
ASP.NET 数据源 数据源 github: https://github.com/ixixii/ASP.NET_03_WebForms 一个 data sourse 控件与数据绑定的控件相互作用 ...
最新文章
- 不相交轮换的乘积怎么求_谁能告诉我 轮换的乘积 怎么做?具体题目是
- 三菱plc232数据线驱动下载_三菱PLC与西门子PLC有什么区别?
- linux显卡驱动mxm,linux下我的FX5200显卡驱动安装
- PresentViewController详解
- wxWidgets:wxDataObjectComposite类用法
- 三图解决phpStorm部署ftp
- 文字转wav_这6款超良心语音转文字工具,真让人省心!
- Javascript屏蔽鼠标的右键的两种方法。
- 现代软件工程讲义 4 团队和流程
- elementUI表单验证
- python程序设计遇到的问题_Python程序设计与实践:用计算思维解决问题
- PHP设计渐变的效果,canvas渐变色:canvas如何实现渐变色的效果?
- Python用户交互以及数据类型
- 是时候考虑怎么用好云了
- foobar 2000|foobar2000中文版32/64位下载 v1.3.16
- python 学习(八—1) 项目:生成随机的测试试卷文件
- C语言程序设计今天下雨了吗,C语言编程模拟下雨by张田浩
- 【java校招你不知道的那些事儿】校招分层级,找准定位很重要
- 如何压缩图片200k以下?
- 自媒体书单:从入门、写作、策划到运营自媒体必须收藏的系列好书
热门文章
- VMDNS服务器未响应,vmware克隆虚拟机后进行网络配置
- html app的登陆、注册,登陆_注册.html
- 2021-01-07 Halcon初学者知识【8】 将图像部分内容截取并保存
- 我眼中的软件测试,交互设计师眼中的软件测试
- mysql 注入用例_mysql-常用注入渗透手法
- mysql主键创建非聚集索引_什么是聚集索引,非聚集索引,索引覆盖,回表,索引下推...
- 之全能忙内_临沧大名山茶:喝过诸多忙肺茶,但你不知道什么是“隔年香”
- Effective C++ --2 构造/析构/赋值运算
- SVM学习(三):线性分类器的求解
- activiti工作流引擎入门教程