通过labview事件结构贩卖机对事件结构常见错误总结(二)
时间:10-02
整理:3721RD
点击:
3. 过度使用局部变量
事件结构一般都是在循环里面的,而程序中好些变量是要在各个事件中都有可能使用到的,不少参赛程序依然大量使用局部变量而没有充分使用循环的移位寄存器。如下图所示:
上图中的“Money”和“Tip”都使用了局部变量,而在其它事件中,也需要使用到“Money”和“Tip”的地方,所以这里完全可以通过移位寄存器来代替局部变量,从而提高程序的效率。如下图所示:
这里也并不是说不能使用局部变量,如果有 N 个事件结构,但只有一个事件才会对“Money”进行处理,那么个人认为 个人认为 个人认为 个人认为也可以使用局部变量,减少移位寄存器的使用和连线。
局部变量的使用除了带来内存的额外开支以外,最重要的是会造成“冒险竞争”,使用局部变量打乱了 LabVIEW 的数据流编程,使程序的可读性变差。全局变量也是同样的道理,NI 也是建议尽量少用或不用局部变量的。 关于局部变量的使用在论坛上有讨论,自带的帮助文件中也多次提到应该少用局部变量,可以搜索一下。
除了使用局部变量以外,也有程序使用“值”属性节点来更新控件的值的:
上图中用“值”属性来更新前面板的控件,这种用法更加不提倡,因为“值”属性节点虽然也能达到更新值的目的,但是属性节点的效率比局部变量更加低下,它不管数据是否需要更新,都会刷新控件的值。
4。 不合理使用顺序结构
似乎还是很多人都喜欢用顺序结构,即使在可以不使用的时候。
上面图 11,第一帧顺序框是弹出所买的饮料的,第二帧顺序框是判断是否需要禁用对应的控件的,这二个功能没有严格的执行顺序要求,完全可以同步执行而不需要使用顺序结构来定义的。 图 12 没有截好,实际上这个顺序结构是在“停止.值改变”的事件结构里面的,按下“停止”后播放退出的声音,同时“停止”按钮输出一个 T,以便停止外部循环进而停止程序。
这里的顺序结构也不是必须的,因为就算不用事件结构,程序也是等“停止值改变”事件结构里面的程序全部执行完后才会将 T 输出到外部循环的循环条件端子的,如果不用事件结构,读取“停止”按钮会跟播放声音同时进行,但只有等声音播放完后,“停止”按钮的 T 才会传到事件结构右边的通道再输入到循环的停止条件端那里。
如果将延时 1 秒的程序放到第二个顺序框,是希望播放完声音后停顿一下再退出程序,还稍微能解释得过去。 图 13 中,第一帧顺序框是禁用控件的,第二帧是读取产生事件的按钮标签文本的,这二部分的程序也不存在严格的执行顺序要求,即不是必须在禁用控件后才能读取按钮文本值。所以这里的顺序框也是可以去掉的。 对于事件结构的使用论坛之前上也一些讨论的,可以用连线来定义各部分程序的执行顺序,具体可以在论坛中搜索“顺序结构”。
5.在程序中存在不少数据类型的强制转换
在 LabVIEW 中,如果输入的数据类型与期待的数据类型不一致,会由LabVIEW 进行强制的数据类型转换,同时在转换的节点处生成一个小红点,提示用户此处进行了数据的强制转换。 类型转换会产生两个问题:增加了类型转换时间,需要开辟新的 BUFFER,增大了内存空间的使用。特别是对于多元素的数组或簇,类型强制转换时的代价更加大
备注:如果不是大的数组或簇,且强制转换不是发生在快速循环里面的话,单个数值的强制类型转换对性能的影响是微乎其微的,但应该养成良好的编程习惯。
7 没有注重代码的重用
这个似乎没办法截图说明。 在用户选择某种饮料后,大部分的程序都会弹出一个子界面,提示用户已经购买了这种饮料,用户点击界面后就退出这个界面。问题就出在这里,如果有多种饮料可以选择的话,就要求弹出的饮料图片也需要这么多种,这时,大部分程序的做法是使用多个子 VI,每个子 VI 的界面对应一种饮料的图片。如果有 5 种饮料就要有 5 个子 VI,这种做法对于代码重用方面来说是非常不提倡的,因为这 5 个子 VI 的功能、动作完全一样,唯一不同的就是在不一样的情况下界面不一样,因此这里就可以考虑使用图片控件或其它方法,根据输入的不同而选择不一样的界面。
7.没有给将同一类控件的事件源设置在同一个事件分支里面 没有给将同一类控件的事件源设置在同一个事件分支里面 没有给将同一类控件的事件源设置在同一个事件分支里面。
图 16 只使用了 5 个事件分支,下面这个图 17 除了多出的三个功能外,达到图 16 同样的效果,使用了 10 个事件分支,单从程序结构上来分,肯定是第一个图的结构要明朗得多,扩展性也强,试想一下,如果需求后来修改为要一个“20 USD”的按钮和加一个第 5 种饮料,哪一种结构的改动小,改起来更快呢?这里比较事件分支的数量,并不是说分支的数量越少越好,而是说对于同一类的有相同动作的控件应该设置在同一个事件分支里面,一来结构更好,扩展性更强,二来也充分重用了代码。
8.循环加事件结构中,外部循环使用延时
在很多程序中都是在事件结构外面、WHILE 循环里面加了一个延时的,我想是不是受“使用WHILE 循环时最好加一个延时以降低 CPU 占用率”这个说法的影响了,以至于 WHILE 循环中都会添加上一个延时,另外在比赛的程序中也发现了WHILE 循环中没加延时的情况,不知道是不是忘了还是觉得子 VI 不重要就没加了:
像上图中这样只有一个WHILE 循环的,确实是需要加一个延时,以免这个循环占用了太多的 CPU,大家可以试验一下,运行这个程序的时候打开WINDOWS 进程管理器,会发现 CPU使用率为 100%,LabVIEW 就占了 97%以上,如果在循环数 i 上创建一个显件,会发现 i 变化非常快,所以为了不影响其它进程,加一个小小的延时,就算是 1ms 的延时,CPU的使用率马上就接近正常水平了,一般在只使用 WHILE 的用户界面程序中,延时到 200ms 用户都基本上感觉不到程序的响应会有延时。 在没有事件结构之前(6.0 版以前),都是使用下面的方式来检测按钮动作的,截自程序竞赛的范例:
上图是使用搜索一维数组的方法,每隔 250ms 搜索一次前面板的控件,看是否有控件被按下,有按下时再执行对应的操作,因为这里只有一个循环,所以要加一个延时,如果去掉这个延时,同样会导致 CPU被 100%占用的情况。 WHILE+ EVENT 的结构跟单循环的结构的最大区别就是WHILE+ EVENT可以更高效地利用资源,在没有事件发生时,不会检测相关的控件是否发生改变,只有在对应的事件发生后,才会对事件进行处理。仅有WHILE 循环的结构是一种主动检测的方式,不管有没有事,过一段时间都得去看看,就像老板不信任自己的手下一样,总是找机会去看一下有没有在聊 QQ;WHILE+ EVENT 呢,是一种被动的处理方式,就像中断,告诉他有事了,他才会处理,就好像你平时工作,老板轻易不管你,你说程序写完了或者要加工资了,他才跑过来看一下。 所以,在WHILE+EVENT 中,不需要在WHILE 里面 EVENT 外面加延时,对结构理解有误还是小事,有时候还会影响程序,比如让控件随鼠标移动而移动时,需要处理鼠标移动等连续发生的事件,如果在 EVENT 外部加一个延时,就很难达到我们要的效果了。 另外,有显示所购买的饮料那个子 VI 里,也有一些程序没有使用事件结构而仍然使用一个WHILE 循环来循环检测退出按钮,因为这次竞赛的目的就是为了让大家更好地理解、使用事件结构来代替原来的WHILE 循环来编程,所以能用事件结构优化的程序,最好都使用WHILE+EVENT 这种结构来实现,养成这个习惯,平时的对话框之类的程序,都可以用上这样的结构。 有程序在 “购买”事件分支里面也使用了延时:
这里也不应该使用延时的,这部分程序应该是越快执行完越好,事件发生后,尽快处理完,然后可以尽快执行超时事件分支更新前面板控件的禁用属性。以前也见过在初始化数组的 FOR循环里面添加延时的,如下图所示,也是不必要的。
9.没有为退出按钮设置一个事件分支
日常程序中像上面二个图这样的程序也有一些,就是将停止按钮直接连接到外层WHILE 循环的停止端子上,这种做法在这次的程序中基本上不会有什么问题,因为都会加上一个“超时”的事件分支,这样如果按下停止按钮后,即使程序在当前循环中已经读过停止按钮(此时为 F)的值了,但是在下一次循环中仍然可以读到停止按钮的 T 值,从而停止程序。 但这种做法可以说是没有完全理解事件结构,我们在初学事件结构的时候,一般都曾经这样连接过循环的停止条件端,但是在没有设置超时事件分支的程序中,会发现按下了停止按钮后程序并没有停止,而是再次触发了二次事件后,程序才会停止,之前论坛上也发过这样的贴子讨论这个问题的。这是因为这里的 “停止”按钮跟事件结构是并行的,用高亮执行会非常清楚,一运行到循环后,程序会先读取“停止”按钮的值(按数据流的执行顺序),此时“停止”=F,同时运到事件结构,但此时事件肯定还没有发生,就等待事件发生,如果这时按下停止按钮,则程序不会停止,因为程序还在等待事件的发生,这时触发其中一种事件,则执行对应的事件分支,执行完后进入下一次循环,再次读取“停止”=T,虽然是输出 T 给循环的停止端子了,循环也准备停止了,但因为事件结构还没有执行,所以等到再有事件触发,执行完对应程序后才会停止程序。 这次的程序中直接连接停止到循环的停止端子的程序,之所以没有出现停止不了的现象,是因为都设置了超时端子,发生超时事件时用户感觉不到,实际上
程序还是在按下停止按钮后运行了至少一次超时事件的。
正确的做法是为“停止”按钮设置一个独立的“值改变”分支,这样,不管有没有超时分支,只要停止按钮被按下,事件结构就会响应,然后输出 T 给循环的停止端子从而停止循环。
了解更多labview事件结构请进入:http://bbs.elecfans.com/topic-labviewevent.html
学习了啊!也就是说设置while循环的停止最好用事件结构“停止”分支,如果我while循环里的是顺序结构,是不是也要用事件结构“停止”分支?
想看看,学习一下
学习啦 谢谢
学习了
受益匪浅
好东西啊 必须顶
非常好 解决了新手的细节问题