百度空间 | 百度首页 
 
查看文章
 
容易忽略的多条件状态问题
2009-08-25 01:27

      今天检查游戏引擎代码时发现一个不怎么起眼却会影响整个系统的问题,最终用了一个简单的方式做了了结。

      这个问题在这里暂时称之为“多条件状态问题”。

      我们常常会有这样一种需求,某个事件触发的前提有多个操作,每个操作都是一个独立的行为。那么为了让我们的代码更加优雅,我们通常把每一个操作封装成一个独立方法。然后再用一个方法来调用这些独立的方法,最后发出一个完成的事件。

      为了更加准确的理解,我们可以想象现在我们要发射一枚运载火箭,假定发射前我们需要做一些准备才能发射。

      1、电力系统检查
      2、通讯系统检查
      3、分离器检查
      4、加注主推进燃料
      5、加注辅助推进器燃料

      最后通知准备完毕——点火。

      用程序简单表示一下:

      public function 发射初始化()
      {
            电力系统检查();
            通讯系统检查();
             分离器检查();
            加注主推进燃料();
            加注辅助推进器燃料();

            dispatchEvent(new Event("发射就绪"));
      }

       private function 电力系统检查()
      {
            ……
      }

       private function 通讯系统检查()
      {
            ……
      }

       private function 分离器检查()
      {
            ……
      }

       private function 加注主推进燃料()
      {
            ……
      }

       private function 加注辅助推进器燃料()
      {
            ……
      }

      写完之后感觉流程清晰,代码优雅。看起来貌似没有问题了,而且也确实在大多数情况下你几乎看不出有什么问题。

      然而真的是这样吗???

      仔细分析,你会发现由于我们把繁琐的方法封装到了一个个独立的方法里面。尽管在方法的执行上,他是顺序的。但是你却忽视了至少两点:

      第一点:方法被依次执行,但是并非是我们想象的第一个方法执行完才执行第二个,而是第一个执行后开始执行下一个。

      换句话说第一个方法开始后,没有等到结束第二个就开始了,然后第三个、第四个。。。这与我们所期望的是完全背离了。

      第二点:或许“准备就绪”的事件已经发出了,而我们上面的各个发射准备却还在进行。这相当恐怖了。

      那么为什么很多时候我们测试的时候我们发现不到呢?因为我们的各个独立方法中的逻辑并不复杂不属于耗时操作,所以“准备就绪”事件发出后,点火程序执行时正好前面的准备完毕了。所以火箭顺利发射出去。

解决方案:
      现在我们知道了问题的所在,你一定开始想办法解决了。最简单的方式我们可以吧这个过程改成顺序执行的,即一个条件完成之后再进行下一个(有点像自己分配运行时间片段)。继续拿发射火箭举例,就好像总指挥喊话:
      “检查电力系统”
       “电力系统检查启动。。。动力系统检查完毕!”
       “检查通讯系统”
      “通讯系统检查启动。。。通讯系统检查完毕!”
       。。。。。。

      “所有检查完毕,可以发射”
      “点火——”

      我们还可以用另一种方式来实现,使用非顺序的事件通知的方式解决。怎么理解?

       现在,总指挥面前出现了5个开关,只有5个开关都打开,点火按钮才可以按下。现在的口令模拟一下如下:
      “开始发射准备”
      “电力系统一切正常” 总指挥打开1号开关
       “通讯系统一切正常” 总指挥打开2号开关
      “主推进燃料加注完毕” 总指挥打开4号开关
      “辅助推进燃料加注完毕” 总指挥打开5好开关
      “分离系统检查完毕,一切正常” 分离系统检查需要花比较长时间,这个时候才完成。总指挥打开3号开关
      5个开关都打开,此时总指挥“准备完毕,点火”,按下了点火按钮。

非顺序方式的好处

      比较一下上面的两种方式,你会发现非顺序的通知方式或许更加容易扩展,因为我们只要加一个开关就行了。

      按照上面的思路,我们用二进制的每一位来表示一个开关,二进制的位上为1表示这个条件已经满足。程序我们这样来写。

      private var status:int;
      public function 构造函数()
      {
            addEventListener("准备就绪",火箭准备);
            ……
      }

      public function 发射初始化()
      {
            电力系统检查();
            通讯系统检查();
             分离器检查();
            加注主推进燃料();
            加注辅助推进器燃料();
      }

       private function 电力系统检查()
      {
            ……
           status=status|1
            dispatchEvent(new Event("准备就绪"));
      }

       private function 通讯系统检查()
      {
            ……
           status=status|2
            dispatchEvent(new Event("准备就绪"));
      }

       private function 分离器检查()
      {
            ……
           status=status|4
            dispatchEvent(new Event("准备就绪"));
      }

       private function 加注主推进燃料()
      {
            ……
           status=status|8
            dispatchEvent(new Event("准备就绪"));

      }

       private function 加注辅助推进器燃料()
      {
            ……
           status=status|16
            dispatchEvent(new Event("准备就绪"));

      }

      private function 火箭准备()
      {
            if((status&31)==31) dispatchEvent(new Event("点火"));
      }


类别:flash开发 | 添加到搜藏 | 浏览() | 评论 (8)
 
最近读者:
 
网友评论:
1
2009-08-30 23:52 | 回复
很不错。但是FLASH不是单线程的么?按常理应该是调用一个方法,应该是等待该方法执行完后再执行第二个调用。不过我没有去证明过,有时间去实践证明一下,再来跟你确认一下哈!~~如果真存在这个问题,那可是大问题哈!~
 
2
2009-08-31 11:31 | 回复
哇~ 这样flash不就变成多线程了么?
 
3
2009-09-04 22:34 | 回复
恩,flash是基于事件的,如果你的其中一个方法采用了事件去做事件,就会出现没有执行完成的东西了
写完了引擎还是要多做些测试的,除了基本的单元的测试之外
我之前就是因为其中一个功能没有做过大量测试,然后急着用
结果就出现bug的,囧~~调试了很就才发现....虽然是小问题
 
5
2009-09-05 10:43 | 回复
回复弃天笑:关于这个问题的还没有仔细考究,我当时也诧异。你这么一说,我看我还是花点时间写个例子验证一下。
 
6
2009-09-14 00:48 | 回复
AS3是单线程的,所以不可能出现两段as3代码同时执行,但是AS3的宿主可以提供多线程,但是仅限部分功能,如加载资源,事件在AS3在swf中的实现也不会改变AS3单线程的现实。
 
7
2009-09-15 23:06 | 回复
回复匿名网友:AS3是单线程的,所以不可能出现两段as3代码同时执行,但是AS3的宿主可以提供多线程,但是仅限部分功能,如加载资源,事件在AS3在swf中的实现也不会改变AS3单线程的现实。

我想你说到了本质上了,回想我上次调试正是在地图加载阶段出现了这种问题。看来一定要好好查个究竟。谢谢提供线索。抽空有了结果会贴出来看看。
 
8
2009-09-20 21:47 | 回复
弄个函数队列就行了。
 
9
2009-11-13 11:49 | 回复
结论就是这个flash多线程执行函数导致没有按照预期顺序执行的问题是虚惊一场,谢谢大家的讨论,希望mr可以介绍一些asunit的东西,先谢谢
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu