我正在寻找 Perl 中良好的计时器实现。我遇到的情况是这样的:我需要跟踪许多文件的 I/O 事件,并且对于那些在足够长的时间内保持不变的文件,将对它们采取删除操作,因此高效的计时器实现对于 我现在正在参与的应用程序。为了避免重复造轮子,请先向你们寻求帮助。
最佳答案
Time::HiRes附带 perl。
此外,您的应用程序听起来可以受益于 Linux::Inotify (注意前面的Linux::)。当为要在一定时间不活动后删除的文件设置计时器时,请记住上次访问的时间。在 inotify 事件 Hook 中,将此时间更新为当前时间。然后,您可以定期检查文件的生命周期是否已过期,而无需对您跟踪的所有文件进行统计。当然,在到期时,您可以添加最终检查以确保没有出现任何问题。
如果您有大量正在运行的文件,您可能需要按过期时间对文件列表进行排序。这使得定期检查过期变得微不足道。
更新:我刚刚用 Linux::Inotify 做了一些实验。使用这种方法事情并不像我想象的那么容易。首先,这是部分工作的代码,我没有时间完成。
#!/usr/bin/env perl
use strict;
use warnings;
use List::Util qw/min max/;
use Time::HiRes qw/time sleep/;
use Data::Dumper;
use Linux::Inotify;
# [s], but handles subsecond granularity, too
use constant CLEANUP_INTERVAL => 1.;
use constant FILE_ACCESS_TIMEOUT => 5.;
# for fast and readable struct access
use constant FILENAME => 0;
use constant ACCESSTIME => 1;
use constant WATCHER => 2;
my $notifier = Linux::Inotify->new;
my @tracked_files = populate_tracked_files(\@ARGV, $notifier);
warn Dumper \@tracked_files;
while (1) {
# update the tracked files according to inotify events
my @events = $notifier->read;
my %files_seen_this_round;
foreach my $event (@events) {
$event->print();
my $ev_filename = $event->{name}; # part of the API, apparently
# we mave have multiple events per file.
next if $files_seen_this_round{$ev_filename}++;
# find and update the right tracked file
# TODO: this could be optimized to O(1) with a hash at
# the cost of more bookkeeping
foreach my $tfile (@tracked_files) {
if ($tfile->[FILENAME] eq $ev_filename) {
my $atime = $^T + 60*60*24 * -A $ev_filename; # update access time
$tfile->[ACCESSTIME] = $atime;
# a partial bubble sort would be hugely more efficient here!
# => O(n) from O(n*log(n))
@tracked_files = sort {$a->[ACCESSTIME] <=> $b->[ACCESSTIME]}
@tracked_files;
last;
}
} # end foreach tracked file
} # end foreach event
cleanup_files(\@tracked_files);
sleep(CLEANUP_INTERVAL);
last if not @tracked_files;
} # end while(1)
$notifier->close;
sub cleanup_files {
my $files = shift;
my $now = time();
for (my $fileno = 0; $fileno < $#{$files}; ++$fileno) {
my $file = $files->[$fileno];
if ($now - $file->[ACCESSTIME] > FILE_ACCESS_TIMEOUT) {
warn "File '" . $file->[FILENAME] . "' timed out";
# remove this file from the watch list
# (and delete in your scenario)
$file->[WATCHER]->remove;
splice @$files, $fileno, 1;
$fileno--;
}
}
}
sub populate_tracked_files {
my $files = shift;
my $notifier = shift;
my @tracked_files;
foreach my $file (@$files) {
die "Not a file: '$file'" if not -f $file;
my $watch = $notifier->add_watch($file, Linux::Inotify::ALL_EVENTS);
push @tracked_files, [$file, $^T + 60*60*24*-A $file, $watch];
}
@tracked_files = sort {$a->[ACCESSTIME] <=> $b->[ACCESSTIME]}
@tracked_files;
return @tracked_files;
}
时间检查逻辑中仍然存在一些错误。但主要问题是 $notifier->read()
将阻塞,直到出现新事件。而我们实际上只是想看看是否有新事件,然后继续清理。这必须添加到 Linux::Inotify 作为文件描述符的非阻塞读取。自the author is no longer interested起任何人都可以接管模块的维护.
关于perl - Perl 有什么好的定时器实现吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2987712/