Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading perl线程异常退出_Multithreading_Perl_Exit - Fatal编程技术网

Multithreading perl线程异常退出

Multithreading perl线程异常退出,multithreading,perl,exit,Multithreading,Perl,Exit,我正在使用perl的模块和一个简单的爬虫,这样我就可以并行下载页面。局部地,我会收到如下错误消息: 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/perl

我正在使用perl的模块和一个简单的爬虫,这样我就可以并行下载页面。局部地,我会收到如下错误消息:

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.
当我在没有线程的情况下线性运行脚本时,我不会遇到这些错误。这些错误看起来几乎像来自模块,但它们似乎不应该导致线程异常退出。在使用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);
}

perl确实有一种中止和执行fatal()的机制。但我不认为你是这样

如果查看threads.pl第101行,这可能是线程退出方法,使用非零退出状态可能会被视为异常情况

我认为这些都是无害的,使用“异常终止”只是表明手术没有100%成功。这意味着您应该为那些操作未完成的线程规划和实施恢复场景

对您来说,词语的选择是令人担忧的,但如果您将消息改为:“线程123未完成表示成功”,它可能看起来不那么令人担忧,更符合正在发生的情况

最好允许threadmain方法返回(必要时在途中释放数据)。这不是使用threads::exit,当然,除非这是作为main方法中的最后一件事来完成的


关于分叉,您是否声称它在分叉时从不失败,分叉过程是否以非零“退出状态”指示失败。另外,您确定在使用线程时没有使网站、代理、网络等过载。

我对您的源代码进行了一些研究,得出了以下结论:

#!/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
  • 我为每个线程分配一个用户代理,而不是为每个请求分配一个
更好的风格:

  • 我使用
    unde
    发出线程终止的信号:一旦一个假值退出队列,循环条件无论如何都是假的,线程终止。如果要将特殊字符串传递给信号终止,则应使用
    while(1)
    循环,并在循环体中退出队列
重要:

  • 为了消除这些讨厌的错误,我
    eval
    'd
    get
    。如果请求
    消失了
    ,我的线程不会跟进,而是保持冷静并继续
因为
get
ting URL实际上可能会消亡。如果我们查看的第51行,我们会看到,如果无法为连接创建套接字,将引发致命错误。当主机名无法解析时,可能会发生这种情况

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


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

看起来
get
方法正在设置
$@
,即使它没有死亡。您可以在
get
之后添加一些指纹来查看它是否正在消亡:

my $RESP = $ua->get($todo);
if($RESP->is_success) {
    print "$todo success\n";
} else {
    print "$todo failed: ".$RESP->status_line."\n";
}
在线程退出前仍发生失败请求后,您可以看到打印:

http://www.collectorsarmoury.com/ success
http://burgundywinecompany.com/ success
http://beetreeminiatures.com/ failed: 500 Can't connect to beetreeminiatures.com:80 (Connection timed out)
Thread 3 terminated abnormally: Can't connect to beetreeminiatures.com:80 (Connection timed out)

$@
被设置为异常时,线程退出将显示为拾取。如果在退出线程之前重置
$@
(或
Handle\u Work
中的
local$@
,或
eval
周围的
get
),线程将干净地退出。

hmmm…但是如果线性下载URL或通过分叉方式下载URL,则不会给出此错误消息。没有办法阻止线程终止?是的,当分叉时,进程不会不规则地失败。而且我不太可能过载网站的代理/网络/等等,因为我测试数据中的每个url都位于不同的网站。不,分叉不表示退出状态为非零的故障。它正常终止。如果你确定,可能是任何东西,程序错误,设计错误,perl错误。你需要弄清问题的症结所在。你是否确保每个线程都有一个新的实例?审核代码以确保每个线程中没有共享任何内容,每个线程都需要初始化自己的perl对象,传入的内容很少(如URL),并且不应访问任何共享的globals变量。我怀疑问题只是设计错误。@DarrylMiles,我在上面发布了一个导致错误的示例脚本。我很确定这个sampel脚本中没有共享任何内容,但我仍然得到了错误。好的,脚本很好,至少我们可以看到您正在做什么。您在$workq中只放置了4个项目,但是您启动了10个线程,每个线程可以处理多个项目。第四个线程不太可能看到任何工作要做。目标站点是否由您拥有/管理?你怎么知道他们没有连接洪水控制装置?原始错误中的线程数如果是连续的,则表示超过10个。可能会将当前线程的开始/停止和处理的作业总数添加到子例程中,也会在所有输出中发出threads->tid()。您可能会看到问题