【问题标题】:Writing a persistent perl script编写持久的 perl 脚本
【发布时间】:2012-05-08 07:12:08
【问题描述】:

我正在尝试编写持久/缓存脚本。代码看起来像这样:

...
Memoize('process_fille');
print process_file($ARGV[0]);
...
sub process_file{
    my $filename = shift;
    my ($a, $b, $c) = extract_values_from_file($filename);
    if (exists $my_hash{$a}{$b}{$c}){
        return $my_hash{$a}{$b}{$c};
    }
    return $default;
}

将在循环中从 shell 脚本中调用,如下所示

value=`perl my_script.pl`;

有没有一种方法可以让我调用这个脚本来保持它的状态。从一个电话到另一个电话。让我们假设初始化 '%my_hash' 和调用 extract_values_from_file 都是昂贵的操作。

谢谢

【问题讨论】:

  • IMO 这取决于脚本的使用频率。如果它只是不时运行,请使用序列化技术。如果它不止于此——例如,它正在服务于某种关键的、可能是实时的相对目的——让它成为一个持久的后台服务器/使用 IPC。

标签: linux perl bash unix


【解决方案1】:

您无法让脚本保持状态。一旦进程存在,任何未写入磁盘的信息都会消失。

您可以通过以下几种方式完成此操作:

  • 编写一个监听网络或 unix 套接字的守护进程。守护进程可以填充my_hash 并回答从一个非常简单的my_script.pl 发送的问题。它只需要打开与守护程序的连接,发送问题并返回答案。

  • 创建高效的查找文件格式。如果您经常需要这些信息,它可能仍会保留在 VFS 缓存中。

  • 设置共享内存区域。当您的脚本第一次启动时,您将信息保存在那里,然后再使用它。不过,从 Perl 脚本来看,这可能很棘手。

【讨论】:

    【解决方案2】:

    如果您的示例中的 %my_hash 在其最终初始化状态下大小适中,您可以简单地使用序列化模块之一,如 StorableJSON::XSData::Dumper,以在运行之间保持数据为预组装形式。当它不存在时生成一个新文件,并在它存在时从那里重新加载准备好的内容。

    另外,您提到您会循环调用此脚本。一个好的策略是不要在循环内立即调用脚本,而是构建一个参数队列,然后在单次执行的循环之后将所有参数传递给脚本。脚本会设置它的环境,然后循环遍历参数来完成简单的工作,而无需为每个参数重做设置步骤。

    【讨论】:

      【解决方案3】:

      没有。不是直接的,但可以通过很多方式实现。

      1) I understand **extract_values_from_file()** parses given file returning hash.
      2) 1 can be made as a script, then dump the parsed hash using **Data::Dumper** into file.
      3) When running my_script.pl, ensure that file generated by 2 is later than of the config file. Can achieve this via **make**
      3.1) **use** the file generated by 2 to retrieve values.
      

      同样可以通过冻结/解冻来实现

      【讨论】:

        【解决方案4】:

        这是一种黑魔法,但您可以在脚本的 __DATA__ 令牌之后存储状态并将其持久化。

        use Data::Dumper; # or JSON, YAML, or any other data serializer
        package MyPackage;
        my $DATA_ptr;
        our $state;
        INIT {
            $DATA_ptr = tell DATA;
            $state = eval join "", <DATA>;
        }
        
        ...
        manipulate $MyPackage::state in this and other scripts
        ...
        
        END {
            open DATA, '+<', $0;   # $0 is the name of this script
            seek DATA, $DATA_ptr, 0;
            print DATA Data::Dumper::Dumper($state);
            truncate DATA, tell DATA;  # in case new data is shorter than old data
            close DATA;
        }
        __DATA__
        $VAR1 = {
            'foo' => 123,
            'bar' => 42,
            ...
        }
        

        INIT 块中,存储文件__DATA__ 部分的开头位置并反序列化您的状态。在END 块中,您重新序列化当前状态并覆盖脚本的__DATA__ 部分。当然,运行脚本的用户需要对脚本有写权限。

        编辑为使用INIT 块而不是BEGIN 块——DATA 块在编译阶段未设置。

        【讨论】:

        • 序列化状态 - 是的。在你自己内部重写它——该死的不!这可能看起来很时髦并产生 +1 或 2,但维护起来完全是一团糟。
        • 非常酷,但打印到您的实际源代码文件似乎不健康。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-22
        • 2018-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多