2011年7月16日,第二稿
5.1 数据流——图形化语言运行机制
我们知道,图形化语言的运行机制是基于数据流的。所以图形化语言的编程思想(编程的思维方式)也应该是数据流概念的延伸。数据流编程是一种全新的编程方式,所以在学习或使用LabVIEW图形化编程语言时,最重要的就是必须建立数据流编程的基本概念。
5.1.1 何谓数据流
从计算机的发展过程可以看出,计算机的硬件体系架构对计算机编程语言有着深远的影响。长期以来,绝大多数计算机编程语言都是依据冯.诺伊曼硬件体系架构来设计的,这种类型的语言被称为命令式(过程式)语言。以汇编语言为例,它就是基于冯.诺伊曼硬件体系运行机制的一种抽象,它把程序看作是由若干行动指令和变量组成的有序列表,并用变量来存储数据,用语句来执行指令。这种命令式(过程式)的程序,其运行机制是基于控制流的,所以也被称为控制流编程。
尽管LabVIEW图形化编程语言也是基于冯.诺伊曼硬件体系架构,但它在创建图形化代码之初就确定为基于数据流运行机制,也被称为数据流编程。这是图形化语言与传统编程语言不同之处。
实际上,数据流编程是一种软件体系架构,它最初存在于电子表格数据处理软件中。在电子表格中,我们可以指定某个公式依赖于电子表格中某些行、列单元格中的数值(公式在后台进行计算),当这些单元格中的任何一个数值发生改变时,电子表格会按公式自动重新进行计算,从而得到新的、准确的计算结果。
LabVIEW的发明者强烈地感觉到基于电子表格的数据流对于图形化软件系统存在着一些非常潜在的可利用价值。因此他们发明、创造出了基于数据流的图形化代码,还包括获得美国专利的、现代结构化程序设计中的基本构件——图形化的循环等,从而创造出图形化编程语言LabVIEW。
电子表格中的数据流是一种隐式运行方式,我们直观上看不到。而图形化语言的数据流是一种显式的运行方式。在例2-1中我们已经看到了这种显式的运行方式,字符串通过连线从左向右传递到字符串显示控件。
下面通过一个图例来进一步说明控制流编程与数据流编程间的不同之处[10]。
尽管LabVIEW图形化编程语言也是基于冯.诺伊曼硬件体系架构,但它在创建图形化代码之初就确定为基于数据流运行机制,也被称为数据流编程。这是图形化语言与传统编程语言不同之处。
实际上,数据流编程是一种软件体系架构,它最初存在于电子表格数据处理软件中。在电子表格中,我们可以指定某个公式依赖于电子表格中某些行、列单元格中的数值(公式在后台进行计算),当这些单元格中的任何一个数值发生改变时,电子表格会按公式自动重新进行计算,从而得到新的、准确的计算结果。
LabVIEW的发明者强烈地感觉到基于电子表格的数据流对于图形化软件系统存在着一些非常潜在的可利用价值。因此他们发明、创造出了基于数据流的图形化代码,还包括获得美国专利的、现代结构化程序设计中的基本构件——图形化的循环等,从而创造出图形化编程语言LabVIEW。
电子表格中的数据流是一种隐式运行方式,我们直观上看不到。而图形化语言的数据流是一种显式的运行方式。在例2-1中我们已经看到了这种显式的运行方式,字符串通过连线从左向右传递到字符串显示控件。
下面通过一个图例来进一步说明控制流编程与数据流编程间的不同之处[10]。
数据流是图形化语言中控制节点执行的一种运行机制。与大多数基于文本顺序处理的计算机语言不同,数据流要求节点中可执行代码接收到所有必须的输入数据后,节点才会被执行;另一方面,仅当节点中的代码执行完成后,数据才会流出节点。
节点间的数据是依赖于连线来进行传递的,连线确保所传递的数据类型是一致的。
节点间的数据是依赖于连线来进行传递的,连线确保所传递的数据类型是一致的。
5.1.2 数据流编程
首先我们通过一个程序示例来进一步理解图形化语言数据流编程的特点。为了更直观的起见,我们将所有输入数据都设定为常数。这样我们就可以通过程序框图来了解数据之间的流动关系。
上图的图形化程序中,为创建测量任务的虚拟通道使用了三个VI,它们之间的关系是串行连接(通过错误簇连线可以看出)。而每个VI有多个输入参数(数据),其中有并行连接的,也有单独连接的。
那么程序运行时,数据是如何传递的呢?
设置开发环境高亮和单步运行,我们会看到下图所示的现象。
那么程序运行时,数据是如何传递的呢?
设置开发环境高亮和单步运行,我们会看到下图所示的现象。
程序运行的第一步,三个VI同时接收到所有的数据(每个VI中的小圆点表示数据以被并行接收),而只有第一个VI在等待执行。如果程序继续执行,每个VI将依次运行(串行运行)。
这里可以简单的看成,所有数据都是并行的(同时GET数据),而VI间的运行关系是串联运行的。假如第一个VI没有获得所需的数据,将不会继续运行,直到所有关联的数据全部到达程序才会继续运行。
由于LabVIEW图形化编程语言利用基本代码(节点)重用的方法进行程序设计,并且没有必要的语法说明。所以数据流编程就成为图形化语言的基本编程思想。我们也必须适应这种编程方法和编程思想。这对于习惯于文本编程的人来说应该是一种观念的转变。
这里可以简单的看成,所有数据都是并行的(同时GET数据),而VI间的运行关系是串联运行的。假如第一个VI没有获得所需的数据,将不会继续运行,直到所有关联的数据全部到达程序才会继续运行。
由于LabVIEW图形化编程语言利用基本代码(节点)重用的方法进行程序设计,并且没有必要的语法说明。所以数据流编程就成为图形化语言的基本编程思想。我们也必须适应这种编程方法和编程思想。这对于习惯于文本编程的人来说应该是一种观念的转变。
5.1.3 数据流编程的基本特点
为了更好的了解和理解数据流编程的思想,我们简单总结图形化语言数据流编程的一些特点:
第一,数据流编程是一种显式的编程方式
数据流编程主要对象是接线端、节点和连线。但是节点中的不同连线导致了数据或者并行发生或者串行发生,这些通过程序框图我们可以直观的查看到。所以在设计和分析程序代码时我们要充分注意到这种情况。
这种显式的编程方式基本上是从左向右进行的(特例是反馈节点和移位寄存器),它的运行方式也如此。数据流编程不存在从上到下的编程方式,这一点要给与充分的注意。下面的示例说明了这个问题。
第一,数据流编程是一种显式的编程方式
数据流编程主要对象是接线端、节点和连线。但是节点中的不同连线导致了数据或者并行发生或者串行发生,这些通过程序框图我们可以直观的查看到。所以在设计和分析程序代码时我们要充分注意到这种情况。
这种显式的编程方式基本上是从左向右进行的(特例是反馈节点和移位寄存器),它的运行方式也如此。数据流编程不存在从上到下的编程方式,这一点要给与充分的注意。下面的示例说明了这个问题。
图形化代码是按照从左到右的顺序排放的,运行时会发生什么情况呢?
其实这是两段彼此不相关的代码,尽管是按照从左到右的顺序排放的,但是在程序执行时将会同时执行这两段代码。实际上,用鼠标按动开发环境中工具拦上的(Clean Up Diagram)按键会看到下图所示的情况。
其实这是两段彼此不相关的代码,尽管是按照从左到右的顺序排放的,但是在程序执行时将会同时执行这两段代码。实际上,用鼠标按动开发环境中工具拦上的(Clean Up Diagram)按键会看到下图所示的情况。
上图中的代码会从上到下执行吗?数据流的运行机制告诉我们它们是并行执行的(并行的从左到右执行)。
此例表明,基于数据流编程的程序代码,彼此不相关的程序段是并发同时执行的。所以说图形化语言天生地具有并行执行能力。这点对于测量和控制程序而言实在是太重要了。
第二,数据流程序是命令式执行
数据流程序基本是命令式执行的,通过前面的一些代码可以清楚的看到这一点。但是一些彼此不相关的程序段会是并发同时执行的,这些通过前面的例子也看得很清楚。这就要求我们代码排放要有规矩,避免随意放置代码导致程序运行的逻辑混乱。
连线在执行顺序上起到了至关重要的作用。所以连线的整洁和清晰是设计者必须要引起注意的问题。
第三,变量会破坏数据流的运行机制
因为变量可以随处放置使用,从而导致破坏了图形化语言最基本的数据流运行机制。甚用变量是图形化语言中的一种特殊要求。这也是为什么图形化语言中会出现多种变量的主要原因,目的是尽可能的缩小变量的使用范围。
其实合理的使用变量是可以避免一些问题出现的,比如变量用于初始化状态,同时尽量避免在其它地方改写变量等等。这点需要依赖设计者的警觉性。
第四,输入控件或常数是数据流的源头,显示控件是数据流的终端
我们一定还记得,控件被分为输入控件和显示控件两种。输入控件被作为数据流运行的源头,而显示控件被作为数据流运行的终端。这些特征是图形化语言数据流编程所需要的必然结果。回顾一下我们所创建的子VI,我们也必须使用输入控件和显示控件来定义子VI的接线端。实际上就是确定数据流的输入端和输出端。
此例表明,基于数据流编程的程序代码,彼此不相关的程序段是并发同时执行的。所以说图形化语言天生地具有并行执行能力。这点对于测量和控制程序而言实在是太重要了。
第二,数据流程序是命令式执行
数据流程序基本是命令式执行的,通过前面的一些代码可以清楚的看到这一点。但是一些彼此不相关的程序段会是并发同时执行的,这些通过前面的例子也看得很清楚。这就要求我们代码排放要有规矩,避免随意放置代码导致程序运行的逻辑混乱。
连线在执行顺序上起到了至关重要的作用。所以连线的整洁和清晰是设计者必须要引起注意的问题。
第三,变量会破坏数据流的运行机制
因为变量可以随处放置使用,从而导致破坏了图形化语言最基本的数据流运行机制。甚用变量是图形化语言中的一种特殊要求。这也是为什么图形化语言中会出现多种变量的主要原因,目的是尽可能的缩小变量的使用范围。
其实合理的使用变量是可以避免一些问题出现的,比如变量用于初始化状态,同时尽量避免在其它地方改写变量等等。这点需要依赖设计者的警觉性。
第四,输入控件或常数是数据流的源头,显示控件是数据流的终端
我们一定还记得,控件被分为输入控件和显示控件两种。输入控件被作为数据流运行的源头,而显示控件被作为数据流运行的终端。这些特征是图形化语言数据流编程所需要的必然结果。回顾一下我们所创建的子VI,我们也必须使用输入控件和显示控件来定义子VI的接线端。实际上就是确定数据流的输入端和输出端。
5.1.4 数据流编程的深入理解
图形化语言的数据流编程有着自身的独特之处,应该在学习中引起我们的注意。我们学习某些知识过程中,经常会采用对比学习的方法。比如C语言中的变量应该对应图形化语言中的那些元素等。关于图形化语言中变量这个问题前面我们已经讨论过。这里我们看看其它方面还存在的一些问题。
作为控制流的C语言代码有时候无法直接与基于数据流的图形化代码相比较。我们看看下面的例子。
例 5-1 C语言中常见的语句(1)
在C与言中,下面的语句也是较为常见的语句
int A,B;
A=5;
B=A;
按图形化语言来理解,A=5;表示A应该是一个显示控件,常量5传递给A。而B=A;要求将A中的数据传递给B,显然A应该是一个输入控件。
我们知道,控件绝对不可以同时处于两个状态。所以图形化语言无法直接表示这样的关系(通过变量和属性节点可以实现这样的表达方式)。
例 5-2 C语言中常见的语句(2)
我们再看下面这样的C语言代码。
int i =5 ;
i=i + 1 (类似于i=++i)
如此清晰的C代码,用图形化代码如何直接表示?
例 5-3 C语言中常见的语句(3)
我们再看下面这样的C语言代码。
int A,B,SUM;
A=20;
B=50;
SUM=A+B
这样的C代码,用图形化代码又如何直接表示?
上面几个例子说明我们不能用基于控制流的C代码来直接类比基于数据流的LabVIEW图形化代码。因为它们的表现手法和运行机制是不相同的,比如图形化语言中的输入控件和显示控件是两个不同的对象(但不是变量),具有各自独立的数据存储地址。或者说C语言需要这样的编程方式而图形化语言则不需要。
图形化程序如何贯彻数据流的编程思想以及图形化程序如何控制程序流将是我们下面所要讨论的内容。
作为控制流的C语言代码有时候无法直接与基于数据流的图形化代码相比较。我们看看下面的例子。
例 5-1 C语言中常见的语句(1)
在C与言中,下面的语句也是较为常见的语句
int A,B;
A=5;
B=A;
按图形化语言来理解,A=5;表示A应该是一个显示控件,常量5传递给A。而B=A;要求将A中的数据传递给B,显然A应该是一个输入控件。
我们知道,控件绝对不可以同时处于两个状态。所以图形化语言无法直接表示这样的关系(通过变量和属性节点可以实现这样的表达方式)。
例 5-2 C语言中常见的语句(2)
我们再看下面这样的C语言代码。
int i =5 ;
i=i + 1 (类似于i=++i)
如此清晰的C代码,用图形化代码如何直接表示?
例 5-3 C语言中常见的语句(3)
我们再看下面这样的C语言代码。
int A,B,SUM;
A=20;
B=50;
SUM=A+B
这样的C代码,用图形化代码又如何直接表示?
上面几个例子说明我们不能用基于控制流的C代码来直接类比基于数据流的LabVIEW图形化代码。因为它们的表现手法和运行机制是不相同的,比如图形化语言中的输入控件和显示控件是两个不同的对象(但不是变量),具有各自独立的数据存储地址。或者说C语言需要这样的编程方式而图形化语言则不需要。
图形化程序如何贯彻数据流的编程思想以及图形化程序如何控制程序流将是我们下面所要讨论的内容。








