gpt4 book ai didi

multithreading - perl线程异常退出

转载 作者:行者123 更新时间:2023-12-01 11:49:03 24 4
gpt4 key购买 nike

我正在使用 perl 的 threads我正在开发一个带有简单爬虫的模块,这样我就可以并行下载页面。偶尔,我会收到如下错误消息:

Thread 7 terminated abnormally: read timeout at /usr/lib64/perl5/threads.pm line 101.
Thread 15 terminated abnormally: Can't connect to burgundywinecompany.com:80 (connect: timeout) at /usr/lib64/perl5/threads.pm line 101.
Thread 19 terminated abnormally: write failed: Connection reset by peer at /usr/lib64/perl5/threads.pm line 101.

当我在没有线程的情况下线性运行脚本时,我没有遇到这些错误。这些错误几乎看起来像是来自 LWP::UserAgent模块,但它们似乎不应该导致线程异常退出。使用 perl 的线程时,我必须采取一些额外的预防措施吗?谢谢!

更新:

我已经追踪到这些异常终止的来源,而且似乎是每当我使用 LWP::UserAgent 发出请求时。如果我删除下载网页的方法调用,那么错误就会停止。

示例脚本

下面的脚本会导致我所说的一个错误。最后一个 URL 将超时,导致本应属于 HTTP::Repsonse 对象的内容反而导致线程异常终止:

#!/usr/bin/perl
use threads;
use Thread::Queue;
use LWP::UserAgent;

my $THREADS=10; # Number of threads
#(if you care about them)
my $workq = Thread::Queue->new(); # Work to do

my @stufftodo = qw(http://www.collectorsarmoury.com/ http://burgundywinecompany.com/ http://beetreeminiatures.com/);

$workq->enqueue(@stufftodo); # Queue up some work to do
$workq->enqueue("EXIT") for(1..$THREADS); # And tell them when

threads->create("Handle_Work") for(1..$THREADS); # Spawn our workers

$_->join for threads->list;

sub Handle_Work {
while(my $todo=$workq->dequeue()) {
last if $todo eq 'EXIT'; # All done
print "$todo\n";
my $ua = LWP::UserAgent->new;
my $RESP = $ua->get($todo);
}
threads->exit(0);
}

最佳答案

我对你的来源进行了一些研究并得出了这个结论:

#!/usr/bin/perl

use 5.012; use warnings;
use threads; use Thread::Queue; use LWP::UserAgent;

use constant THREADS => 10;

my $queue = Thread::Queue->new();
my @URLs = qw( http://www.collectorsarmoury.com/
http://burgundywinecompany.com/
http://beetreeminiatures.com/ );
my @threads;

for (1..THREADS) {
push @threads, threads->create(sub {
my $ua = LWP::UserAgent->new;
$ua->timeout(5); # short timeout for easy testing.
while(my $task = $queue->dequeue) {
my $response = eval{ $ua->get($task)->status_line };
say "$task --> $response";
}
});
}

$queue->enqueue(@URLs);
$queue->enqueue(undef) for 1..THREADS;
# ... here work is done
$_->join foreach @threads;

输出:

http://www.collectorsarmoury.com/ --> 200 OK
http://burgundywinecompany.com/ --> 200 OK
http://beetreeminiatures.com/ --> 500 Can't connect to beetreeminiatures.com:80 (timeout)

没有eval的输出:

http://www.collectorsarmoury.com/ --> 200 OK
http://burgundywinecompany.com/ --> 200 OK
http://beetreeminiatures.com/ --> 500 Can't connect to beetreeminiatures.com:80 (timeout)
Thread 2 terminated abnormally: Can't connect to beetreeminiatures.com:80 (timeout)

LWP::Protocol::http::Socket: connect: timeout at /usr/share/perl5/LWP/Protocol/http.pm line 51.

我做的不同的事情是:

不重要:

  • 我没有退出我的线程;我只是在最后放弃(隐式 return)
  • 我为每个线程分配一个用户代理,而不是为每个请求分配一个。

更好的风格:

  • 我使用 undef 来指示线程终止:一旦 false 值出队,循环条件无论如何都为 false,线程终止。如果你想传递一个特殊的字符串来终止信号,你应该用while (1)循环,并在循环体内出队。

重要:

  • 为了消除那些讨厌的错误,我evalget。如果请求死亡,我的线程不会效仿,而是保持冷静并继续。

因为 get URL 实际上会死掉。如果我们查看 source of LWP::Protocol::http 的第 51 行,我们看到如果无法为连接创建套接字,则会引发 fatal error 。当无法解析主机名时,可能会发生这种情况。

在我的代码中,我决定忽略错误(因为我已经打印了状态行)。根据问题的不同,您可能想再次重试该 URL,或者给出一个信息更丰富的警告。有关错误处理的良好示例,请参阅链接源。

不幸的是,我无法重现您的确切错误(您的警告中给出的行指向 threads->exit() 类方法)。但是在大多数情况下,使用 eval 应该可以防止异常终止。

关于multithreading - perl线程异常退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13438740/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com