管道-过滤器体系结构模式为处理数据流的系统提供了一种结构
–
工业中的流处理系统-水处理系统
–
整个系统分为多个处理单元,由管道将多个处理单元连接起来;管道用来输送流,处理单元用于流的加工和处理;流从一个处理单元出口输出,
经过管道输送到下一个处理单元的入口,经过每个处理单元的加工处理,最后由输出管道输出到使用地。
•
软件系统中管道
-
过滤器结构的应用
—
操作系统
–
UNIX
系统中,可以将某个命令的标准输出与另一命令的标准输入相连。
•
语法:命令
1 |
命令
2 |
命令
3 | … |
命令
N
•
例如:
ls
–l | more
–
Windows
•
Dir
*.exe | sort > exe.txt
–
软件系统中管道
-
过滤器结构的应用
—
传统的语言编译器
•
结构描述
–
数据流的处理过程分成几个顺序执行的处理步骤,每个处理步骤由一个过滤器组件实现。每个过滤器组件有一组输入和一组输出。
–
每个过滤器组件都会对输入的数据采用渐进方式进行局部处理,一个过滤器组件的输出是下一个过滤器的输入。
–
系统的初始数据流由数据源(
DataSource
)输入,系统的处理结果数据流输出到数据池(
Data Sink
)。
–
数据源、过滤器和数据池由管道
pipe
顺序连接起来,每个管道承担相邻过滤器之间的数据传输。
•
主要组成:
–
过滤器
Filter
–
数据源
Source
–
数据池
Sink
–
管道
Pipe
•
过滤器
Filter
–
封装数据处理功能的功能单元,是管道
-
过滤器结构中的主要处理单元。
–
每个过滤器组件有一组输入和一组输出,从连接它的
输入管道
中读取数据,数据经过加工处理,输出到连接它的
输出管道
。
•
过滤器
Filter
–
3
种激活方式
•
pull
拉出式
–
后续组件从当前过滤器中拉出数据。
•
push
推入式
–
前邻组件向当前过滤器推入数据。
•
主动过滤器
ActiveFilter
–
激活状态下,以循环方式不断从前邻组件中拉出数据,并向后续组件推入数据。
•
管道
Pipe
–
管道是相邻过滤器之间的连接。
–
连接两个主动过滤器的管道是一个先进先出的缓冲器,用以完成同步。
–
连接被动过滤器的管道可以通过对被动过滤器的调用来实现。
•
数据源
DataSource
–
数据源是系统的输入。向系统提供
相同结构或类型
的数据序列。如标准输入流、文本文件或传感器采集的数据等。
–
数据源可以主动把数据推入过滤器,也可以在过滤器需要数据时被动地提供数据。
•
数据池
DataSink
–
汇集系统处理的结果数据。如文本文件、数据库、标准输出等。
–
主动数据池把过滤器的结果拉出来,而被动数据池等待过滤器把结果推入进来。
•
实现的主要步骤
1.
把系统任务分成几个独立的处理阶段。
2.
定义沿着每个管道传输的数据格式。
3.
决定管道的连接。
4.
设计和实现过滤器。
5.
设计出错处理。
6.
建立、处理流水线。
•
步骤
1
:把系统任务分成几个
独立
的处理阶段。
–
每个处理阶段完成一个独立的处理功能。
–
每个处理阶段必须只依赖其前一阶段的输出。
•
步骤
2
:定义沿着每个管道传输的数据格式。
–
如果整个系统定义统一的数据格式,则使得过滤器组件的重组变得容易,系统可以获取极大的灵活性。但是,单一的数据格式在某些情况下,在不同的过滤器组件择偶观需要频繁进行格式转换,大大降低了系统的数据处理效率。
–
如果需要选择不同的数据格式,又需要一定的灵活性,则需要在系统中建立专门的格式转换过滤器组件。
•
步骤
3
:决定管道的连接。
–
首先,需要确定把过滤器作为
被动过滤器
还是
主动过滤器
来实现。
–
被动过滤器的连接简单,一般
直接使用
调用来拉出或推入数据即可。需要注意的是,重组和替换过滤器组件时必须设计代码修改,另外这种过滤器难以独立开发和测试。
–
使用主动过滤器,可以借助管道的同步化分离机制提高系统的灵活性。如果所有的管道都使用这种方式,系统的过滤器可以做到随意重组。
•
步骤
4
:设计和实现过滤器。
–
过滤器的设计必须同时考虑
需要完成的任务
,和
与它相邻的管道
。
•
如果是被动过滤器,拉入数据可以通过函数(
function
)实现,推出数据可以通过过程(
process
)实现。如果是主动过滤器,可以实现为线程(
Thread
)。
•
在
过程
1
之间和在地址空间之间的数据复制的需要,会影响到系统的性能;因此,管道缓冲区的大小是一个值得考虑的附加参数。在多个关联转换和数据复制总开销一定情况下,使用小的主动过滤器组件,可以获得较高的灵活性。
•
为了方便重用过滤器组件,需要控制过滤器组件行为时,可以通过下列常用方式将参数传递给相应的过滤器组件:
–
在命令行传递参数。
–
在启动过滤器组件时,让过滤器使用可以访问得到的
全局环境或者仓库
2
,这些可以通过操作系统、配置文件或者
shell
程序来支持实现。
•
设计和实现过滤器时,要注意
灵活性和易用性的均衡
,一般一个过滤器只需做好一件事即可。
•
步骤
5
:设计出错处理。
–
管线(
pipeline
)上的组件不能共享全局状态,但错误可以探测到。
•
例如,在
unix
系统中,为错误消息定义了一个特殊的输出通道
stderr
1
;
但是,当多个过滤器组件并行运行时,
stderr
会以不可预测的方式混合来自不同过滤器组件的错误信息。
–
错误处理实现比较困难。
•
如果一个过滤器组件在输入数据中探测到错误,它可以忽略后面输入的数据,直到明确的分隔符出现为止。因此,当可能会有不可预料的输入数据时,如果允许容忍不精确的结果,这种错误处理的方法还是很有效的。
•
重启系统,希望继续运行
à
再同步问题
à
添加
固定标识。
•
步骤
6
:建立处理流水线
–
如果系统只需处理单一任务,可以用一个主程序来创建管道流水线,由主程序调用主动过滤器启动处理过程。
–
增加灵活性:
•
通过提供
shell
程序或用户终端工具,使用它们从你的过滤器组件集中装配出不同的流水线。
•
如果允许中间处理结果存放到文件中,并支持把文件作为后续组件的输入,这样可以支持流水线的增量式开发。
•
如果系统中的过滤器严格限制为
单输入、单输出
,则这种结构的系统被称为
管线或流水线(
pipeline
)
。
•
如果允许过滤器的输入或输出多于一个,这种系统的结构可以用一个有向图表示。这种系统的结构需要经过严格的理论分析,以保证系统可以终止和输出正确结果。
•
在过滤器之间使用命名的管道(如文件)传送数据,这种系统称为
有名管道
。有名管道限制过滤器之间数据传送只能在命名的管道中,给系统的维护和重组带来了困难。
•
优点
–
系统易于重组,增加了系统的灵活性。
–
系统易于更新、升级和维护。
–
过滤器组件易于重用。
–
并行处理提高了系统的效率。
–
支持快速原型系统的设计和实现。
–
系统具有清晰的拓扑结构,方便进行某些系统性能的分析。
•
缺点
–
管道
-
过滤器结构会经常导致数据的批处理方式。
–
管道
-
过滤器结构不适合处理交互式应用要求。
–
数据转换增加了系统的开销和复杂性。
–
共享状态信息代价高且不灵活。
–
用并行方式获得高效率往往不可行。
–
难于进行错误处理。