2

次のように Perl ライブラリHTTP::Asyncを使用しています。

use strict;
use warnings;
use HTTP::Async;
use Time::HiRes;
...
my $async = HTTP::Async->new( ... );
my $request = HTTP::Request->new( GET => $url );
my $start = [Time::HiRes::gettimeofday()];
my $id = $async->add($request);
my $response = undef;
while (!$response) {
  $response = $async->wait_for_next_response(1);
  last if Time::HiRes::tv_interval($start) > TIME_OUT; 
}
...

ループがタイムアウトしてスクリプトが終了するwhileと、次のエラー メッセージが表示されます。

HTTP::Async object destroyed but still in use at script.pl line 0
HTTP::Async INTERNAL ERROR: 'id_opts' not empty at script.pl line 0

私のオプションは何ですか?HTTP::Async オブジェクトがまだ使用されているが不要になった場合、どのように「クリーンアップ」できますか?

4

2 に答える 2

1

より一般的なソリューションとしてHTTP::Asyncをサブクラス化することはそれほど難しくありません。これを使用して、保留中のすべてのリクエストを中止できるようにします。

package HTTP::Async::WithFlush;
use strict;
use warnings;    
use base 'HTTP::Async';
use Time::HiRes qw(time);

sub _flush_to_send {
  my $self = shift;
  for my $request (@{ $self->{to_send} }) {
    delete $self->{id_opts}->{$request->[1]};
  }
  $self->{to_send} = [];
}

sub _flush_in_progress {
  my $self = shift;
  # cause all transfers to time out
  for my $id (keys %{ $self->{in_progress} }) {
    $self->{in_progress}->{$id}->{finish_by} = time - 1;
  }
  $self->_process_in_progress;
}

sub _flush_to_return {
  my $self = shift;                                                                 
  while($self->_next_response(-1)) { }
}

sub flush_pending_requests {
  my $self = shift;
  $self->_flush_to_send;
  $self->_flush_in_progress;
  $self->_flush_to_return;
  return;
}

1;

これは、@ ikegamiによるコードよりも、モジュールの内部を使用する方が(多分)簡単です。

于 2012-08-20T12:22:10.600 に答える
1

リクエストを不完全にすることをお勧めしますremoveが、モジュールはそうするためのインターフェースを提供していません。


オプション 1 : 削除機能を追加します。

以下をスクリプトに追加します。

BEGIN {
    require HTTP::Async;
    package HTTP::Async;

    if (!defined(&remove)) {
        *remove = sub {
            my ($self, $id) = @_;

            my $hashref = $self->{in_progress}{$id}
                or return undef;

            my $s = $hashref->{handle};
            $self->_io_select->remove($s);
            delete $self->{fileno_to_id}{ $s->fileno };
            delete $self->{in_progress}{$id};
            delete $self->{id_opts}{$id};

            return $hashref->{request};
        };
    }

    if (!defined(&remove_all)) {
        *remove_all = sub {
            my ($self) = @_;
            return map $self->remove($_), keys %{ $self->{in_progress} };
        };
    }
}

作成者に連絡して、この機能を追加できるかどうかを確認してください。$idによって返される値addです。


オプション 2 : デストラクタからのすべての警告を黙らせます。

すべてのリクエストを処理しなくても問題ない場合は、警告を黙らせても問題はありません。次のように実行できます。

use Sub::ScopeFinalizer qw( scope_finalizer );

my $async = ...;
my $anchor = scope_finalizer {
    local $SIG{__WARN__} = sub { };
    $async = undef;
};
...

これにより、オブジェクトの破壊中に発生するすべての警告が無音になることに注意してください。

于 2012-05-14T17:30:32.247 に答える