【问题标题】:perl - two stage conditional compilationperl - 两阶段条件编译
【发布时间】:2018-03-05 20:46:59
【问题描述】:

我经常执行相当大的 perl 脚本(来自 cron)。
大多数执行都需要非常简短的测试。

如何将单个文件脚本分成两部分,其中“第二部分”根据“第 1 部分”的决定编译?


考虑的解决方案:

  1. 使用BEGIN{ …; exit if …; } 块进行琐碎测试。
  2. 使用require 编译和执行file_2 的file_1 的两个文件解决方案。
    如果成本合理,我更喜欢单文件解决方案以简化维护。

【问题讨论】:

  • if(condition) { ... }?
  • @el.pescado 它修复了“代码部分”的执行。它不修复“代码部分”的编译
  • 你能量化编译开销是否相关吗?真的是 10k+ 行脚本吗?编译/开始阶段 (perl -c ...) 真的需要几秒钟吗?如果不是,您如何确定这种优化是否相关?
  • 该脚本的运行频率如此之高且运行时间如此之长(数年),恕我直言,它将在整个脚本生命周期内产生影响。

标签: perl


【解决方案1】:

首先,您应该测量编译实际需要多长时间,看看这种“优化”是否必要。如果确实如此,那么既然您说您更喜欢单文件解决方案,一种可能的解决方案是使用__DATA__ 部分的代码,如下所示:

use warnings;
use strict;

# measure compliation and execution time
use Time::HiRes qw/ gettimeofday tv_interval /;
my $start;
BEGIN { $start = [gettimeofday] }
INIT  { printf "%.06f\n", tv_interval($start) }
END   { printf "%.06f\n", tv_interval($start) }

my $condition = 1; # dummy for testing
# conditionally compile and run the code in the DATA section
if ($condition) {
    eval do { local $/; <DATA>.'; 1' } or die $@;
}

__DATA__
# ... lots of code here ...

【讨论】:

  • 编译需要额外的 >100 毫秒 - 脚本使用了相当大的外部模块。我想以最少的代码/脚本更改包含该功能。
【解决方案2】:

我看到了两种实现你想要的方法。最简单的方法是将脚本分为两部分。第一部分将进行简单的测试。然后,如果您需要进行更复杂的测试,您可以“添加”第二部分。这样做的方法是像这样使用eval

<first-script.pl>
...
eval `cat second-script.pl`;
if( $@ ) {
  print STDERR $@, "\n";
  die "Errors in the second script.\n";
}

或者以更健壮的方式使用File::Slurp

eval read_file("second-script.pl", binmode => ':utf8');

或遵循@amon 的建议和do

do "second-script.pl";

请注意doeval 的不同之处在于:

不同之处还在于,使用 do FILE 评估的代码看不到封闭范围内的词法; eval STRING 可以。但是,它是相同的,因为它会在您每次调用它时重新解析文件,因此您可能不想在循环中执行此操作。

eval 将在第一个脚本的上下文中执行,因此任何变量或初始化都可用于该代码。

与此相关,有一个问题:Best way to add dynamic code to a perl application,我前段时间问过这个问题(并在提供的 cmets 和一些研究的帮助下回答了自己。)我花了一些时间来记录我能想到的所有内容任何人(和我自己)都可以参考。

我看到的第二种方法是将您的测试脚本变成一个守护进程,并让 crontab 位在必要时调用这个守护进程。守护进程保持活动状态,因此您可能需要的任何数据结构都将保留在内存中。不利的一面是,这将持续占用资源,因为守护进程将始终运行。

【讨论】:

  • eval read_file($filename) 通常会表示为do $filename (+ error handling),这具有在错误消息中使用正确的文件名和行号的巨大优势。
  • 不推荐File::Slurpissues太多了。
  • 抱歉,我看到了关于错误处理的其他问题:eval `cat second-script.pl`; - 例如如果找不到文件?此外,eval ...; if ($@) {...}has issues,正如已经指出的那样,整个事情可以用do FILE 代替,但是需要its own error handling。 OTOH,您在使用守护程序方面提出了一个很好的观点。
  • @haukex,我正在尝试提供选项。 do 看不到封闭范围内的词法,这可能是使用 eval 的全部意义所在。所有选项都可能有效。人们发表评论的好处是,有很多想法可供遇到相同问题的人使用。
  • 我完全支持 TIMTOWTDI :-) 我并不是说这些选项不好或不应该出现,只是它们需要一些修改/添加来处理错误。
猜你喜欢
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多