Perl中有没有好的计时器实现?

时间:2010-06-07 07:23:58

标签: perl

我正在寻找perl中的好计时器实现。我遇到的情况就像:我需要跟踪许多文件的I / O活动,并且文件保持不变,足够的时间将对它们执行删除操作,因此有效的计时器实现对于 我现在参与的应用程序。为了避免重新创建轮子,请先向你们寻求帮助。

2 个答案:

答案 0 :(得分:6)

Time::HiRes附带perl。

此外,您的应用程序听起来好像可以从Linux::Inotify中受益(请注意前面的Linux ::)。在为一段时间不活动后要删除的文件设置计时器时,请记住上次访问。在inotify事件挂钩中,将此时间更新为当前时间。然后,您可以定期检查文件的生命周期是否过期而不对您跟踪的所有文件执行统计。到期时,您可以添加最终检查,以确保没有任何问题,当然。

如果您有大量的文件在飞行中,您可能希望保留按到期时间排序的文件列表。这使得到期的定期检查变得微不足道。

更新:我刚刚对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开始接管模块的维护。

答案 1 :(得分:3)

您的程序显然是事件驱动的,您可以使用事件驱动的框架(例如POE或AnyEvent)来实现它。那些具有处理I / O事件和计时器事件的所有部分。