【问题标题】:How to trigger a function once, and only once...?如何触发一个功能一次,而且只有一次......?
【发布时间】:2010-09-26 03:44:03
【问题描述】:

我经常只想触发某个函数一次,但我需要从另一个重复调用的函数中触发它。例如,拍摄某物的快照以备后用。我通常通过设置一个全局布尔值来做到这一点。

我想知道我这样做的方式是否真的是最好的方式?

我似乎记得读过全局变量不好,全局布尔变量更糟糕!

不管怎样,我通常是这样完成触发某个方法一次的:

在我最初的一组变量中...

private var myStatus:Boolean = false;

然后,在经常被调用的函数中......

if (!myStatus) {
    doMyFunction();
    myStatus = true;
}

这对我来说似乎很合乎逻辑,但它是正确的吗?

更新:嗯,根据我从您的回答中了解到的情况,我现在不是检查全局布尔变量,而是首先检查 XML 节点是否存在(我将图像存储在 XML 结构中在发生任何写入磁盘之前),如果没有,那么我将使用 base64 编码的图像数据附加一个新节点。我仍然设置了一个布尔标志,以便稍后我可以在需要时用用户编辑的图像数据覆盖空白图像。它完美地工作。谢谢大家的帮助!

我现在也对在某些情况下使用该特定(线程不安全)系统感到更加自在。

【问题讨论】:

    标签: language-agnostic loops boolean


    【解决方案1】:

    在 Perl 5.10 或更高版本中,您将使用 state 变量。

    use 5.010;
    
    sub test{
      state $once = 1;
    
      if( $once ){
        $once = undef;
        say 'first';
      } else {
        say 'not first';
      }
    }
    
    test for 1..5;
    

    输出

    第一的 不是第一 不是第一 不是第一 不是第一

    【讨论】:

      【解决方案2】:

      当你调用一个函数时,它应该按照你期望的那样处理你给它的参数。如果您以完全相同的方式调用一个函数两次,您应该期望该函数给您相同的结果或执行相同的操作。

      将这种调用一次的依赖项移到多次调用您的函数的逻辑可能会更好。如果您只需要调用一次该函数,则只需调用一次。或者,将不同的参数传递给函数以表明您正在做不同的事情。

      【讨论】:

      • 但是,如果函数返回 case 语句的结果,并且您希望其中一个 case 语句仅在第一次返回时才能够运行函数,该怎么办?还是我还没有得到它?
      • @defmeta:我认为他的意思是考虑为什么你只运行一次代码。如果要进行设置,也许您可​​以通过将设置移到更早的阶段来简化。如果您正在缓存一个可能永远不需要的昂贵结果,那么当然,请在第一次使用时进行。
      • @defmeta: onebyone 是对的——也许你可以更具体地说明你的一次性运行函数需要做什么?调用这个函数有副作用吗?如果你调用它两次会发生什么?
      • 该函数保存用户选择的空白形状的图像,它只能被调用一次,因为在用户编辑完形状后,它不能被另一个空白覆盖。我确实看到还有其他方法可以做到这一点,不幸的是时间不在我这边!
      • 也许您的保存图像函数可能有一个布尔覆盖参数,如果为真,则表示您仅在不存在图像(同名)时才保存。
      【解决方案3】:

      在 C/C++ 中,您通常可以保留这样一个事实,即 doMyFunction() 仅通过使用静态变量封装一次,如下所示:

      void doMyFunction() {
           // gets called only once.
           // side effects go here.
      }
      
      void functionThatGetsCalledALot() {
          static bool called = false;
          if (!called) {
              doMyFunction();
              called = true;
          }
          // do more stuff
      }
      

      这避免了使用全局变量但具有相同的效果,并且静态变量在相关的地方声明,所以很清楚发生了什么。请注意,这不是线程安全的,因此如果您有线程,则需要一个锁。

      【讨论】:

      • 我认为这是错误的。您需要在 functionThatGetsCalledALot 之外声明“被调用”,否则 doMyFunction 将每次都被调用,而不是一次。
      • 不,它是正确的。两者都有效,但使用静态局部变量更干净,因为您不会污染全局命名空间。你真的尝试过运行它吗?查找静态局部变量:en.wikipedia.org/wiki/Local_variable#Static_local_variables
      【解决方案4】:

      它不是线程安全的。这对您来说可能无关紧要,但您确实说过“与语言无关”:您可能不想在 Java 的通用库中使用这种模式。

      这是一个很难以与语言无关的方式回答的问题,因为可用的替代方案在很大程度上取决于语言。例如,在 POSIX 上,如果您需要线程安全,您可以使用 pthread_once。在 C 中,您有静态局部变量来将该布尔值排除在全局范围之外。在任何 OO 语言中,如果您正在拍摄“某物”的快照以供以后使用,那么可能有一个与“某物”(或快照)相对应的合适对象,它可以存储标志。

      【讨论】:

        【解决方案5】:

        这真的取决于你的意思。如果您的代码将从多个线程中调用,那么您就有一个竞争条件,这可能意味着doMyFunction 可以被多次调用。这是因为不止一个线程可以检查myStatus,看到它是假的,然后调用doMyFunction。您可以通过先设置变量来稍微改善一下情况:

        if (!myStatus) {
            myStatus = true;
            doMyFunction();
        }
        

        但这只会缩小问题的窗口,并不能消除它。

        要消除竞争条件,您需要一个锁。

        【讨论】:

        • 好吧,这个特定的实例是在一个相当程序化设计的 Flex 应用程序中,尽管 if 语句在一个 case/switch 语句中,如果有严重的网络拥塞,可以想象它可能会被调用两次。我一定会向上移动变量设置器。谢谢!
        【解决方案6】:

        我没有看到任何其他方式。关于如何改进这一点,唯一想到的是 - 线程安全。但只有当您有多个线程调用该函数时才需要这样做。

        【讨论】:

          【解决方案7】:

          我认为您的方法没有任何问题。请记住,并不总是“正确”的事情......肯定有错误的事情,但正确的事情可能是主观的,也可能取决于系统的要求。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-25
            • 2016-04-21
            • 1970-01-01
            • 2015-12-04
            • 1970-01-01
            • 2012-01-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多