【问题标题】:How to clean-up HTTP::Async if still in use如果仍在使用中,如何清理 HTTP::Async
【发布时间】:2012-05-22 05:03:34
【问题描述】:

我正在使用 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 对象?

【问题讨论】:

  • 请注意 removeremove_all 已添加到 HTTP::Async
  • 感谢@ikegami 的更新...

标签: perl http asynchronous timeout


【解决方案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 的代码更容易使用模块内部。

【讨论】:

    【解决方案2】:

    我建议你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} };
            };
        }
    }
    

    您应该联系作者,看看他是否可以添加此功能。 $idadd 返回的值。


    选项 2:消除来自析构函数的所有警告。

    如果您可以不处理所有请求,那么将警告静音也没有什么坏处。你可以这样做:

    use Sub::ScopeFinalizer qw( scope_finalizer );
    
    my $async = ...;
    my $anchor = scope_finalizer {
        local $SIG{__WARN__} = sub { };
        $async = undef;
    };
    ...
    

    请注意,这将使对象销毁期间发生的所有警告静音,所以我不太喜欢这样。

    【讨论】:

    • @user1215106,它是安全的。这些警告旨在提醒您您要求完成某事但未完成。
    • @user1215106,更新为添加$async->remove_all
    • @user1215106,已修复并经过测试。
    • 你有最新版本(0.10)吗?顺便说一句,它目前不会删除未发送和已完成的请求。
    • 更新到最新版本起到了作用...我不知道到底是什么问题,但现在看起来很好...谢谢!
    猜你喜欢
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 2012-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多