【问题标题】:Perl: Call a Subroutine Every 15 SecondsPerl:每 15 秒调用一次子程序
【发布时间】:2015-12-17 12:46:13
【问题描述】:

所以我一直在这里以及 perl.org 和 perlmaven.com 上四处寻找,但我对正在尝试运行的代码发生的事情感到困惑。我用谷歌搜索了 $SIG 是什么,并在 here 上找到了一些东西,这让我对 local $SIG 是什么有了一些了解,但我仍然对他的意思感到困惑:

Perl 有一个称为 %SIG 的内置散列,其中的键是操作系统中可用信号的名称。这些值是子程序(更具体地说是对子程序的引用),将在特定信号到达时调用。

除了操作系统的标准信号之外,Perl 还添加了两个内部“信号”。其中之一称为 WARN 并且在每次某些代码调用 warn() 函数时触发。另一种叫做DIE,在调用die()时触发。

它还在here 上说我不应该在警报呼叫中混用睡眠呼叫,但在那里解释的内容对我来说似乎是另一种语言。 我很困惑。我无法退出子程序而不会死在我身上。我正在运行的代码是这个(我从这里的另一篇文章中获得它,但我不想恢复那个帖子是从 2011 年开始的):

sub checkfind {
didfindchange;
    while ($call_counter <= 20) {
        my $previous_call_finished = 0;
        eval {
            local $SIG{ALRM} = sub { die "Alarm.\n" };
            alarm 15;
            if ($did_find_change eq "false") {
                didfindchange;
                print("Original FIND value: $original_find_value\n");
                print("FIND value: $ems_find_value\n");
            }
            elsif ($did_find_change eq "true") {
                print("FIND changed.\n");
                print("Original FIND value: $original_find_value\n");
                print("FIND value: $ems_find_value\n");
                $previous_call_finished = 1;
            }
            sleep;
        };
        #Propagate unexpected errors.
        die unless $@ eq "Alarm.\n";
        warn "Timed out!\n" unless $previous_call_finished
    }
    return;
}

我的程序一直死机,我不确定原因。任何帮助,将不胜感激。谢谢!

【问题讨论】:

  • 你为什么要睡觉?就此而言,请用英语描述您正在尝试做的事情
  • 我想每 15 秒调用一次 didfindchange() 。如果 FIND 值改变,退出子程序。如果 FIND 值没有改变,五分钟后退出子程序。我调用 sleep() 是因为由于某种原因,如果我不这样做,子程序就会死掉。 @ysth

标签: perl sleep alarm die


【解决方案1】:

一般来说,对于可能需要很长时间的子程序/外部进程(等待数据库连接、网络资源、计算量非常大的计算等),我们会使用警报。每次任务完成后,您都必须重置警报alarm(0); 对于我理解您正在尝试做的事情,如下所示的简单睡眠/超时循环应该适合您。对于更复杂的事情(等待文件事件、网络事件),您可能希望考虑使用 EV 事件循环 perldoc EV 或 AnyEvent 库 perldoc AnyEvent 进行编程

#!/usr/bin/env perl

use warnings;
use strict;

use constant TIMEOUT => 10;
use constant SLEEP   => 2;

check_for_something();
exit 0; # Success

sub check_for_something {
    my $start_time = time();
    my $elapsed = 0;
    while ( $elapsed < TIMEOUT ) {
        print "$elapsed seconds have elapsed...";
        my $value = look_for_something();
        print "Value is " . ( $value ? 'true' : 'false' ) . "\n";
        if ($value) {
            print "Value is true...returning\n";
            return "value has changed...";
        }

        sleep SLEEP;
        $elapsed = time() - $start_time;
    }
    die "Timed out after " . TIMEOUT . " seconds!\n";
}

sub look_for_something {
    # !! changes the number into either '1' or 'undef'
    # ! !! inverts the sense
    return ! !! int rand (2 * TIMEOUT / SLEEP); # False most of the time, occasionaly true     
}

输出

perl test_find.pl
0 seconds have elapsed...Value is false
2 seconds have elapsed...Value is false
4 seconds have elapsed...Value is false
6 seconds have elapsed...Value is false
8 seconds have elapsed...Value is false
Timed out after 10 seconds!

perl test_find.pl
0 seconds have elapsed...Value is false
2 seconds have elapsed...Value is false
4 seconds have elapsed...Value is true
Value is true...returning

【讨论】:

  • 感谢您的回复,看来您是对的,我不必使用警报。然而,你的回答中有几件事让我很感兴趣。为什么使用 ($start_time) 而不是 $star_time (不带括号)?当您打印 $value 是什么时 ($value ? 'true' : 'false' ) 限制 $value 只能是真还是假?为什么你有两个 check_for_something() 子例程和一个 exit 0;就在一个之下?你能解释一下look_for_something() 的return 语句吗?我对感叹号感到困惑。不管怎样,谢谢你的回复。 @xxfelixxx
  • ($start_time) 周围的括号是不必要的,所以我删除了它们。它们来自于试图避免列表与标量上下文错误的习惯。 $value 设置为1undef,因此我通过三元运算符将其转换为字符串“true”或“false”。第一个check_for_something() 正在调用稍后定义的子程序。 exit 0 是为了让您可以推理代码的流程(仅仅因为您 can 散布代码和子例程,并不意味着它对下一个程序员很好......
  • 至于!!!!!,虽然我不鼓励在任何实际(生产)代码中使用这种结构,但它们是perl 的secret 运算符知识的一部分:search.cpan.org/~book/perlsecret-1.013/lib/perlsecret.pod跨度>
猜你喜欢
  • 1970-01-01
  • 2020-12-07
  • 2019-01-05
  • 2022-01-06
  • 2011-03-17
  • 2021-08-23
  • 2011-04-25
  • 1970-01-01
  • 2021-01-03
相关资源
最近更新 更多