在 Perl 中,如何在没有轮询但有超时的情况下监视文件更改?

Posted

技术标签:

【中文标题】在 Perl 中,如何在没有轮询但有超时的情况下监视文件更改?【英文标题】:How, in Perl, can I watch for file changes, without polling but with timeout? 【发布时间】:2021-07-03 13:56:53 【问题描述】:

我正在使用File::ChangeNotify,它允许 (a) 非阻塞检查更改,或 (b) 阻塞等待更改。我真正想要的是介于两者之间的东西:阻塞并等待更改,但在指定的超时后返回。我不想投票,也不能永远阻止。

如果$watcher->wait_for_events 方法有这样的超时参数就好了,但似乎没有;也许实现跨平台太难了。有什么建议吗?

【问题讨论】:

【参考方案1】:

处理超时的简单方法是alarm 函数。像这样的:

my $timeout = 10;
eval 
    local $SIGALRM = sub  die "alarm\n" ;
    alarm $timeout;
    $watcher->wait_for_events;
    alarm 0;
;
if ($@) 
    die unless $@ eq "alarm\n";   # propagate unexpected errors
    # timed out handling here

【讨论】:

并不是说这是特定于 unix 的,而 File::ChangeNotify 是可移植的。未知的是 OP 和未来读者的要求。【参考方案2】:

你可以把它放到 Perl 可以找到的地方,File::ChangeNotify 会捡起它并使用它。

package File::ChangeNotify::Watcher::WithTimeOut;

use strict;
use warnings;

use namespace::autoclean;

use Time::HiRes qw( sleep );

use Moo;

has watcher      => ( is => 'rw' );
has sleep_cycles => ( is => 'rw' );
has timeout      => ( is => 'rw' );

sub BUILD 

    my ($self, $args) = @_;
    $self->sleep_cycles( delete $args->sleep_cycles );
    $self->timeout( delete $args->timeout || 0 );
    $self->watcher( File::ChangeNotify::Watcher::Default->new( %$args ) );


sub wait_for_events 

    my $self   = shift;

    my $cycles  = $self->sleep_cycles || -1;
    my $timeout = $self->timeout + time; 

    while ( $cycles-- != 0 ) 
    
        my @events = $self->watcher->_interesting_events;

        return @events if @events;
        return @events if $self->timeout && time >= $timeout;

        sleep $self->watcher->sleep_interval;
    


__PACKAGE__->meta->make_immutable;

1;

然后您可以指定timeoutsleep_cycles 参数,当timeout 过期或观察者已睡sleep_cyclessleep_interval 秒时,这些参数将控制权返回给调用者。

use lib qw(./lib);
use File::ChangeNotify;
use Data::Dumper;

my $watcher = File::ChangeNotify->instantiate_watcher ( 
    directories => [ 'C:/Users/holli/testnotify' ],
    filter         => qr/\.(?:pm|conf|yml)$/,
    sleep_interval => 1,
#    sleep_cycles   => 10,
    timeout        => 5,
);

while ( 1 ) 
 
    my @events = $watcher->wait_for_events;
    print Dumper( \@events );

【讨论】:

这至少对 OP 没有帮助。为此,为了帮助 OP,需要一个模块来提供一种异步检查文件更改的机制。它也需要是可取消的。但如果存在这样的模块,OP 可以直接使用它。 @ikegami 现在有一个模块 =) 好多了。 OP 说“我不想投票”,但我相信这只是将对象而不是系统极化。它应该更便宜,尽管它缺乏投票的响应能力。 好吧,如果 OP 不想轮询,那么他们必须一起使用另一个模块。默认观察者做同样的事情: while (1) 检查更新;睡觉

以上是关于在 Perl 中,如何在没有轮询但有超时的情况下监视文件更改?的主要内容,如果未能解决你的问题,请参考以下文章

Perl:如何在没有错误消息的情况下“死”?

如何在没有 root 权限的情况下安装 Perl 模块?

如何在没有存档但有 .dsym 文件的情况下进行符号化?

套接字对、perl、KEEPALIVE 和轮询

Perl在使用警报超时时出现分段错误

如何在没有安装权限的情况下使用新的 Perl 模块?