为什么AnyEvent计时器观察者必须在其回调中被解雇?

时间:2014-03-17 17:36:38

标签: perl timer scope anyevent

在尝试理解AnyEvent的同时,我创建了两个定时器,每次定时器都会在屏幕上被打开。最初都没有工作。但是在Joshua Barratt's timer example之后,我发现如果我没有undef计时器的观察者变量,那么计时器的回调根本不会发生。为什么会这样?我怀疑它与范围在perl和/或AnyEvent中的工作原理有关。

这是我的示例程序:

#!/usr/bin/perl

use AE;

my $cv = AE::cv;

sub func1 {
   my $spoke = 0;
   my $t1; $t1 = AE::timer 0, 1,
      sub { 
         print "Timer 1 Fired\n";
         if($spoke++ > 5) {
            print "Timer 1 Done\n";
            undef $t1;
         }   
      };  
      print "Timer 1 started\n";
}

sub func2 {
   my $spoke = 0;
   my $t2; $t2 = AE::timer 0, 1,
      sub { 
         print "Timer 2 Fired\n";
         if($spoke++ > 5) {
            print "Timer 2 Done\n";
            #undef $t2;
         }   
      };  
      print "Timer 2 started\n";
}

func1();
func2();

$cv->recv;

按原样,我的代码返回:

Timer 1 started
Timer 2 started
Timer 1 Fired
Timer 1 Fired
Timer 1 Fired
Timer 1 Fired
Timer 1 Fired
Timer 1 Fired
Timer 1 Fired
Timer 1 Done

如果我取消注释undef $t2;行,则会触发定时器2的回调,我得到了这个:

Timer 1 started
Timer 2 started
Timer 1 Fired
Timer 2 Fired
Timer 2 Fired
Timer 1 Fired
Timer 1 Fired
Timer 2 Fired
Timer 2 Fired
Timer 1 Fired
Timer 1 Fired
Timer 2 Fired
Timer 2 Fired
Timer 1 Fired
Timer 1 Fired
Timer 1 Done
Timer 2 Fired
Timer 2 Done

1 个答案:

答案 0 :(得分:3)

您必须使守卫对象($t1的值)保持活动状态。如果对它的所有引用都消失了,它将被销毁,并取消该事件。

在闭包中引用$t1会导致闭包捕获它,使其在func结束时保持正常死亡。

如果您想要捕获您不需要的变量,可以使用

$t2 if 0;   # Keep timer alive until process exit.

这是一个简单的闭包示例:

sub make_closure {
   my ($x) = @_;
   return sub {
      print("$x\n");
   };
}

my $f1 = make_closure("Hello, World!");
my $f2 = make_closure("Allo, Jeune Renard!");

$f1->();
$f2->();

注意闭包(anon sub)如何捕获当时存在的$x