perl - Perl 有什么好的定时器实现吗?

标签 perl

我正在寻找 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/

相关文章:

perl - 如何使用 Perl 增量打印字符串?

perl - 打印哈希散列中的最低值

perl - 在 Perl 中获取堆栈跟踪?

perl - Net::SSH::Perl:收到断开连接消息:用户名身份验证失败太多

perl carton cpanfile,可选安装到主 perl 环境

Perl:在 "unless -e"语句中找不到打印变量

perl - 如何停止使用 Win32::Daemon 启动的 Win32 服务?

perl - 使用 exec 的返回代码不会返回

sql - Perl 和 SQLite - 请求改进/优化多个 SQL INSERT 查询

带条件的单行 Ruby 多个语句