32大数据流运行机制中地大数据和简单地大数据处理.docx
《32大数据流运行机制中地大数据和简单地大数据处理.docx》由会员分享,可在线阅读,更多相关《32大数据流运行机制中地大数据和简单地大数据处理.docx(28页珍藏版)》请在冰点文库上搜索。
32大数据流运行机制中地大数据和简单地大数据处理
3.2 数据流运行机制中的数据和简单的数据处理(Operatingmechanisminthedatastreamofdataandsimpledataprocessing)
版本8
创建于:
2010-9-13下午6:
35作者jwdz-最后修改:
2010-9-30下午9:
16作者jwdz
对于任何一种基于文本(控制流)的编程语言,数据类型和数据结构都是必不可少的一个重要组成部分。
而且,在不同种类的编程语言中,它们所包含的数据类型和数据结构大体上都极为相似,如C、Java等。
作为图形化的编程语言,LabVIEW在这点上,与基于文本的编程语言有着许多的相似之处,即包含了近乎完整的数据类型和数据结构。
同时,也会存在着一些不同之处,因为LabVIEW更多的是面向工程应用的程序设计,所以它还包含了一些其它编程语言所不具备的数据类型或数据结构。
数据流——指数据在程序中的流动。
因为我们将数据流编程视为LabVIEW的核心编程思想,那就必须对数据流中的数据有更多的、更深入的了解。
3.2.1 LabVIEW中的数据
我们知道,C语言中的数据通常是放置在变量中。
那么LabVIEW图形化语言中的数据放置在何处呢?
事实上,LabVIEW中的数据类型和数据结构都是包括在控件选板中的控件(包括指示控件)中。
这应该是LabVIEW所特有的,当然这也应该是引起我们更多关注的地方。
为了更有效的进行讨论,这里还有两点需要强调一下:
其一,通过控件和指示控件我们根本无法确定它具体的数据类型,但它的确是放置数据的地方。
其实,这也很好理解,因为关心数据类型的不是用户而是程序的设计者。
其二,我们将数据类型和数据结构统称为:
数据类型,并不准备对它们的含义和差别做更多的解释。
3.2.1.1 前面版——控件及指示控件
前面板上的控件和指示控件的本质类似一个容器,它们也被称为:
对象。
LabVIEW中的数据就是放置在这里。
前面板上的控件和指示控件与程序框图中的端子是一一对应的(端子是控件在程序框图中的映射)。
它们充分的利用了图形化操作系统的所提供的基本特性,逼真的模拟出虚拟仪器所必需的图形化用户界面的基本元素。
它们在前面板上除了起到人机对话的操作和显示之外,还起到了与程序框图中的端子间进行数据传递的作用。
尽管这种传递数据的机理是隐式的、是我们无法察觉的,但它是实是在在的存在的。
同时,它们除了用来存放数据之外,本身还具有众多的属性和方法(包括本地变量和引用)供程序设计时使用(如改变大小、色彩等)。
注意:
这些所有特性都是出现在程序框图中。
在关于控件的这些基本特性请参见下图。
图3.2.1.1-1前面版上的Thermometer指示控件和它的属性
控件作为程序中的一部分在人机对话的过程中使得用户可以直接输入数据。
基于文本的编程语言不具备这种直接性。
采用控件来保存数据可以让您只关注数据以及对数据的操作,并且控件本身抽象出了诸如内存分配和语法规则等大量复杂的计算机编程工作,从而让您的工作效率更高。
3.2.1.2 程序框图——端子(控件的映射)
前面版中控件和指示控件的实例在程序框图上的映射被称为:
端子。
端子类适于基于文本编程语言中的参数和常量。
同样,它本身也具有众多的属性和方法供程序设计时使用。
具体内容请参见下图。
图3.2.1.2-1程序框图上的Thermometer指示控件的端子和它的属性
由于前面版上的控件是提供给用户的,所以控件和指示控件的外貌差别一般并不是很大。
而端子是提供给程序的设计者,所以它所包含的信息较多。
参见下图。
图3.2.1.2-2前面版及程序框图中的控件和端子
在图3.2.1.2-2所示的端子中,我们可以看到端子所提供的一些基本信息:
∙ 控件和指示器的外观图像(也可以以图标的形式显示)
∙ Thermeter、Numeric控件的边框颜色较深,表示它是控件(输入)
∙ Thermeter2、Numeric2控件的边框颜色较浅,表示它是指示控件(输出)
∙ 端子的下方显示出了该控件的数据类型(DBL)
∙ 端子边框上的小箭头可以看出控件的指向(输入或输出)
对比Thermeter2、Numeric2可以看得更明了。
3.2.1.3 控件和端子的指向性(方向性)
基于数据流的运行机制,在LabVIEW中,无论图形化的控件还是端子都具有特殊的指向性(方向性)。
如通过端子边框上的小箭头可以看出该控件的指向(输入或输出)。
这个指向性实际上是表示数据的流入、流出方向,它同样来自数据流编程的需要。
这也表明控件不可以接受数据(只能发出数据),指示控件也不可以输出数据(只能接受数据),因为那样作不符合数据流编程的基本原则。
尽管我们可以随意将一个对象从控件转换成为指示控件,或者反之,但它最终的确定性是唯一的。
也就是说,一个对象不可能同时具备控件和指示控件的功能。
依据数据流编程的基本原则,在程序框图中控件的端子通常是放置在框图中的左侧,而指示控件的端子通常是放置在程序框图的右侧。
而在前面版上,控件和指示控件所放置的位置是不受任意约束的,是可以任意放置的。
顺便说明,本地变量、全局变量、属性等节点也同样因数据流的需要而具有指向性。
3.2.2 LabVIEW中的数据类型
既然LabVIEW中的数据都包含在控件和指示控件中(常量除外),如图3.2.1.2-2中所示的数据类型是DBL,所以数据类型的讨论也就是控件和指示控件的数据类型的讨论。
3.2.2.1 端子所展现的数据类型
首先我们看看LabVIEW2009帮助文件中所提供的以端子的形式表示的控件和指示控件的数据类型。
这种表示方法在程序框图中占用的面积小,并且很直观。
见下图。
图3.2.2.1-1-2用端子表示的控件、指示控件的数据类型
3.2.2.2 用数据分类的方法表示的数据类型
除了上面的数据分类方法外,我们还可以参照LabVIEW给出的另一种分类方式进行分类,就是按照“显示缓存区分配”对话框中的划分方法用控件名直接表示(实质上还是针对控件进行分类)。
选择vi的》工具》性能分析》显示缓存区分配,参见下图。
图3.2.2.2-1显示缓存区分配
分配原则
∙数组控件(Arrays)
表格
波形图
强度图
XY图
混合信号图
∙簇控件(Clusters)
数字波形
错误簇
∙字符串控件(Strings)
字符
树形
组合框
∙路径控件(Paths)
∙标量控件(Scalars)
数值
布尔
枚举
I/O
引用句柄
列表框
LabVIEW对象
容器
∙变体控件(Variants)
∙所有其它类型控件(Allothertype)
时间标识
数字数据
波形
数字波形
数据类型的分类表明了什么样的对象可以彼此相连接在一起。
3.2.2.3 LabVIEW数据类型的转换
从本书的连续性出发,本节似乎有必要存在。
但是当我看到阮先生所著的《我和LabVIEW》一书后,决定放弃本节。
因为那本书中的2.3节内容相当出色(对我同样有着学习和指导的作用)。
遗憾的是目前我还没有找到电子版的,否则可以在这里给出电子版的部分内容。
真正对这方面内容感兴趣的不妨找这本书来看一看。
这里我们仅谈谈数值类型的强制转换。
当我们在某个VI的前面板上放置一个数值控件或一个数值指示器时,该部件的数据类型就已经被赋予一个默认类型。
在前面板上我们是无法看清它所使用的数据类型,但是在程序框图上我们可以清楚地看到它的数据类型。
这些前面已经谈到过。
对于数值型控件的数据类型有多种表示形式,参见下图所示。
关于每种数值类型的具体含义和说明这里就不介绍了。
图3.2.2.3-1DBL数值型控件可选择的数据类型
上图某数值型控件使用的就是DBL数据形式,也就是该控件的默认数据形式(右图中的深色框),完全可以根据需要选择其中的其它的数据类型。
现在我们看另外一个例子。
图3.2.2.3-2数值型数据的强制转换
我们在上图中的下半部“乘”内置函数的数据输入端会发现出现一个小红点。
这种现象在LabVIEW中称为数值类型的强制转换。
在发生数据类型强制转换的地方会出现一个小红点作为提示。
这个提示起到了两个作用:
1、通知用户这里发生了数据的强制转换
据许多资料介绍,在发生强制转换的地方系统自动备份转换前的数据,既系统自动保留一个数据副本,这样的结果将增加内存的使用,特别是在数据是以数组形式出现时。
2、提示用户小心丢失“精度”
数据表示方式的变化有可能损失数据精度,比如从DBL转换为SBL数据时,特别是转换后还需要大量的复杂计算时,可能导致计算误差的累积。
这是工程设计人员特别需要注意的地方。
所以在程序调试时要格外关注这样的提示,尽可能的消除“小红点”,这样可以减少内存使用和提高程序运行速度,并保持合理的运算结果。
3.2.3 LabVIEW中的数据处理
这里所说的数据处理是指通过图形化运算符进行的简单的操作运算。
运算操作也兼有控制程序流的功能,如比较内置函数等。
下面的讨论中,当与其它基于文本的编程语言进行对比时,我们基本上选择C或Java语言。
由于我从来没有使用过它们,所以可能会有理解上错误的地方,欢迎指正。
3.2.3.1 简单的运算操作处理
同其它编程语言的运算符一样,加(+)、减(-)、乘(*)、除(/)都为基本数值运算操作。
所不同的是图形化的运算内置函数表达的方式更清晰、更直观。
参见下图。
图3.2.3.1-1 基本运算操作符
由于图形化代码的特点,运算符的优先序(先乘除,后加减)取决于设计者自身的思维习惯(初等教育的结果)。
例:
3.2.3.1_1操作符的优先序
如公式A=X+(Y-1)/(Z+2)的图形化表示方法见下图。
图3.2.3.1-2操作符的优先序
运算符还支持数组操作,见下例。
例:
3.2.3.1_2数组和常数相加
图3.2.3.1-3-4数组与常数相加(减法略去)
例:
3.2.3.1_3数组和常数相乘
图3.2.3.1-5-6数组与常数相乘(除法略去)
注意:
数组与数组相操作时请注意数组的个数是否相一致。
这里我们想到了波形数据,它的内部包含了一个数组。
那我们看看波形数据与运算符的操作结果。
例:
3.2.3.1_4波形数据和常数相加
图3.2.3.1-7-8 波形数据与常数相加(或相减)
波形数据与常数相加,其结果相当于给波形加了一个偏置(相当于电路中的一个直流偏置),波形的其它性质不发生变化。
白色的是原来的信号(以零为参考点),红色的是加入了一个偏置后的合成波形(如果是减,波形向下移动)。
例:
3.2.3.1_5波形数据和常数相乘
图3.2.3.1-9-10 波形数据与常数相乘(或相除)
波形数据与常数相乘,其结果相当于对原波形进行放大(相当于一个增益),波形的其它性质也不发生变化。
白色的是原来的信号,红色的是加入了一个增益后的波形(如果是除,相当于增益小于1,波形被衰减)。
例:
3.2.3.1_6波形数据的自相加
图3.2.3.1-11-12波形数据的自相加,其结果是相当于上图。
例:
3.2.3.1_7波形数据的自相乘
图3.2.3.1-13-1 波形数据的自相乘,相当于电路中的对信号进行功率计算。
3.2.3.2 赋值(指派)
赋值的含义很好理解,这里就不多谈了。
首先,我们来看看下面的例子:
例:
3.2.3.2._1
在C与言中,下面的语句是较为常见的语句
int A;
A=5;
在LabVIEW中可用下面的图形化代码表示,常数5赋予指示控件A。
图3.2.3.2-1赋值
从图3.2.3.2-1中我们会发现图形化代码的几个特点:
∙在图形化代码中,常数的指向总是从左向右的,直接传送给指示器或下一个节点。
这也是数据流运行机制所要求的。
∙在图形化代码中,“等号”不见了。
取而代之是从左到右的线段,线段的图形和颜色表示不同的图形化的数据类型并代表了基本的赋值功能。
∙在图形化代码中,数据是单流向的。
总是从左到右的流动。
这也就意味着,我们不可能从指示器A中直接读取数据(通过属性节点和本地变量、全局变量可以做到这点),尽管它是一个存放数据的地方。
这是一个很重要的新概念。
我们再来看一个例子,只需对上例进行简单的修改。
例:
3.2.3.2_2
在C与言中,下面的语句也是较为常见的语句
int A,B;
A=5;
B=A;
如此清晰的代码(文本)可是用图形化代码我确无法直接表示出来。
因为在A=5的情况下,A是一个指示控件。
而在B=A的情况下,A应该是一个控件(B是一个指示控件)。
这样处理的结果对吗?
图3.2.3.2-2 这样处理对吗?
与此相类似还有,请看下面的例子。
例:
3.2.3.2_3
我们看下面这样的C语言代码。
int i=5;
i=i+1 (类似于i=++i)
也是如此清晰的C代码,用图形化代码如何直接表示?
下面的表示方法对吗?
图3.2.3.2-2 表示的对吗?
显然,这是不对的。
通过上面的例:
3.2.3.2_2和例:
3.2.3.2_3说明我们不能用基于控制流的C代码来直接类比基于数据流的LabVIEW图形化代码。
尽管有些代码之间可能是可以直接对比的。
这也是我们为什么总是强调数据流的原因所在。
这里也引出了一个大家比较关心的问题,那就是控件是C语言中的变量吗?
3.2.4 LabVIEW中的变量
在LabVIEW中,控件类似基于文本的程序语言中的变量吗?
要解答出这个问题,首先要搞清楚程序语言中变量的准确定义。
3.2.4.1 程序中的变量
程序中的变量是计算机的存储单元或者是对计算机一系列存储单元的具体抽象。
程序员通常认为变量是存储地址的名子,但是就变量本身而言,变量比其名子具有更重大的意义。
从机器语言到汇编语言的发展过程中,很大程度上是用变量名代替绝对数字的存储地址的发展,这样使得程序的可读性更好,因而也就使得程序更加容易编写和维护。
因为将变量名转换成实际地址的编译器也选择这些地址,所以也就规避了绝对地址的问题。
可以使用6种属性来描绘一个变量:
变量名、地址、值、类型、生存期、作用域。
这样一个简单的概念用如此众多的属性来表述看起来似乎太过于复杂,但正是这6种属性提供了一种最清晰的方式来解释变量的各个方面。
这里我们不想讨论所有的6个属性,只讨论我们所关心的前3个,变量名、地址和值。
变量名
在基于文本的编程语言中,变量名是用来标识程序中某些实体的字符串。
但是在使用中要避开“关键字”和“保留字”(不同的语言要求不同)。
地址
变量的地址是与这个变量相关联的存储地址。
值
一个变量的值是与这个变量相关联的存储单元中的内容,它是可以被读出或写入的。
我们可以很方便地将计算机的存储器设想成抽象的单元,而非实际的物理单元。
通过这些简单的了解之后,再回到我们的命题。
3.2.4.2 LabVIEW中的控件是变量吗?
就LabVIEW中的控件而言,由于图形化语言本身高度的抽象结果,导致它的许多特性被隐藏、包装起来。
如控件名我们可以随意的选取,也无须关心存放数据的具体地址,唯一所关心的就是控件中的数据。
那么LabVIEW中的控件可以看作是变量吗?
其实在撰写这部分内容之前,我也曾经一度认为LabVIEW中的控件可以被看作是变量,甚至为此还写过一些东西来力主这样的观点。
当我试图用LabVIEW图形化语言来表述例:
3.2.3.2_2和例:
3.2.3.2_3时,发现这是不可能直接表述出来的(参考图3.2.3.2-1和图3.2.3.2-2)。
这也就意味着:
LabVIEW中的控件是不可以理解为传统意义上的变量,至少它不可以直接作为变量来使用。
简单的说,它是存放控件中数据的地方。
其实这个道理很简单,基于文本语言中的变量指代的是某地址或地址段中的数据。
在控制流运行机制下变量中的数据是可任意读、写的。
而图形化语言是基于数据流的运行机制,控件本身是具有指向性的。
换句话说,控件在不同的使用场合就已经从形式上被分成的控件和指示控件,这样它们的数据存放地址是不一样的。
我们无法直接使一个控件同时还具备指示控件的功能(当然利用其它方法如属性节点和本地变量何以实现这样的功能)。
正因为如此,无法用图形化程序来直接表述例:
3.2.3.2_2和例:
3.2.3.2_3所期待的内容也就不足为怪了。
在LabVIEW2009中,已经不为指示控件分配内存(在LabVIEW8.6之前的版本中一直是为指示控件分配内存的)。
参见下图。
图3.2.4.2-1LabVIEW8.6中的内存分配
图3.2.4.2-2LabVIEW2009中的内存分配
尽管LabVIEW2009中已经不为指示控件分配内存,但它是依然存在的,取决于前端的数据源的地址。
下图诠释的很清楚。
图3.2.4.2-3LabVIEW2009指示控件中的数据依赖于前端的数据
现在,我们给出这样的基本结论:
由于数据流的运行机制,导致LabVIEW中的控件和指示控件是各自独立的对象(数据地址不同),所以它们不可以直接作为变量来使用(直接读或写)。
3.2.4.3 如何获得LabVIEW控件中的值?
前面谈到过,控件和指示控件可以保存数据,但我们不能直接向控件中写入数据,也不能直接从指示控件中读出数据。
那么如果需要对这些数据进行处理时应该如何操作呢?
尽管我们不可以直接将控件作为变量来使用,但是利用它的属性和创建本地变量还是可以间接实现变量的简单功能的(从中获得数据或写入数据)。
利用属性节点获得控件中的值,参见下图。
图3.2.4.3-1利用属性节点获得控件的值
我们可以通过属性节点来获得控件中的值,由于属性节点也具有指向性,所以我们是可以间接进行数据的读或写。
从图3.2.4.3-1可以看出:
∙利用控件的属性节点可以读写控件中的数据(利用属性节点的指向性)
∙使用属性节点内存的使用量比单纯变量的大,内存分配包括了输出型的属性节点的数据和错误簇。
这就提示我们,在具体应用时最好将错误簇链接在一起。
一是满足了数据流的要求,二是避免开辟更多的存储空间。
图3.2.4.3-2错误簇连接后减少了内存分配
利用本地变量也可以获得控件中的值,参见下图。
图3.2.4.3-3利用本地变量获得控件的值
我们可以也通过本地变量来获得控件中的值,由于本地变量也具有指向性,所以我们同样是可以进行读或写。
从图3.2.4.3-3可以看出:
∙利用控件的本地变量可以读写控件中的数据(利用本地变量的指向性)
∙使用本地变量实质是对控件重新分配内存,内存分配包括了输出型的本地变量。
∙本地变量会破坏数据流运行机制
尽管我们使用属性节点和本地变量获得了控件中的数据,但是这与变量相比还是有很大的区别的,如内存使用、破坏数据流等等。
其实,属性节点和本地变量之间也还有很多不同之处。
下面就它们的传值的特性我们来对比看一看。
关于数据竞争的问题几乎所有LabVIEW学习的教材和书籍都强调在程序设计中慎用本地变量(全局变量)。
因为它们的使用破坏了数据流的运行机制,可能导致竞争发生。
其实如果我们充分的认识到这一点,进行合理的设计和使用是没有任何问题的。
关于这点后面还将会谈到。
现在了解了属性节点和本地变量我们在回过头来看看例:
3.2.3.2