Perl - 在多线程程序中使用LWP

时间:2015-07-03 14:52:24

标签: multithreading perl lwp

这是我的代码:

use LWP;
use threads;

use strict;
use warnings;

my @thrds;

for (1..100)
{
    push @thrds, threads->create( 'doit' );
}

for (@thrds)
{
    $_->join();
}

sub doit
{
    LWP::UserAgent->new->get("http://dx.doi.org/10.1002/aoc.1067");
}

我使用的是Windows 7 x64和ActivePerl 5.20.2 x64,我也试过了StrawberryPerl。 我有很多错误:

  

线程...异常终止:无法定位对象方法" _uric_escape"通过包" URI"在... / URI.pm第81行

     

字符串找到运算符预期在(eval 10)第8行,接近" croak'用法:$ io-> getlines()'"

     

(你需要预先宣布呱呱叫吗?)

如果我添加

sleep 1;

push @thrds, threads->create( 'doit' );

它没关系。

问题是什么?

4 个答案:

答案 0 :(得分:2)

我不确定原因,但处理动态加载的模块似乎存在问题。在创建线程之前显式加载它们可以解决问题。换句话说,添加以下内容:

use Carp qw( );
use URI  qw( );

答案 1 :(得分:1)

认为这里的问题将是内存占用。毕竟,您正在加载LWP库,然后将您的流程克隆100次。

与流行的看法相反,perl中的线程甚至不是远程轻量级的。它们不适合这种使用模式 - 每个线程都是您的流程的“完整副本”,而这只是......不是一个好的计划。

我的perl副本 - ActivePerl 5.20.2 - 没有出现同样的问题(我不认为 - 我实际上并不想垃圾邮件列出你所列的网站)。

我建议您改写使用Thread::Queue的线程和较低程度的并行度:

use strict;
use warnings;
use LWP;
use threads;
use Thread::Queue;

my $workers = 10;

my $work_q = Thread::Queue->new();
my $url    = "http://localhost:80";

sub worker_thread {
    while ( my $url = $work_q->dequeue ) {
        LWP::UserAgent->new->get($url);
    }
}

threads->create( \&worker_thread ) for 1 .. $workers;

for ( 1 .. 100 ) {
    $work_q->enqueue($url);
}
$work_q->end;

foreach my $thread ( threads->list ) {
    $thread->join();
}

否则,基于fork的方法也可能更好:

use strict;
use warnings;
use Parallel::ForkManager;
use LWP;

my $manager = Parallel::ForkManager->new(10);

for ( 1 .. 100 ) {
    $manager->start and next;
    LWP::UserAgent->new->get("http://localhost:80");
    $manager->finish;
}

$manager->wait_all_children;

编辑:

对您的示例进行更多测试 - 我在运行5.20.2

的RHEL上遇到类似的运行时错误

它们有所不同,这确实意味着必须有某种竞争条件在这里发生。

这很奇怪,因为线程假设是独立的而它们不是。

特别是 - 我的内核炸弹由于内存耗尽导致内存耗尽而导致'杀死',这是不使用此方法的一个很好的理由。

我使用RHEL和Perl 5.20.2运行代码的测试用例也会引发问题(偶​​尔)。

我得到的是类似的错误 - 偶尔。我看不出明显的消息来源。它可能就像打开文件描述符太多或消耗太多内存一样简单。这是一个非常沉重的记忆负担。

答案 2 :(得分:0)

使用 Mojolicious 框架非常简单。 Mojo::UserAgent类设计为在Mojo::IOLoop模块的帮助下异步工作,虽然同步事务可用但它们是使用标准异步调用的特殊情况实现的

<div id="small-img" class="text-center col-xs-12 col-sm-12 col-md-12 col-lg-12 pagination-centered footer-bottom-img">
  <ul >
    <li>
        <img class="img-responsive inline-block center-block" alt="" src="ssl_secure.png">
    </li>
    <li>
        <img class="img-responsive inline-block center-block" alt="" src="secure-cc-paypal.png">
    </li>
    <li>
        <img class="img-responsive inline-block center-block" alt="" src="gt-secured-seal.gif">
    </li>
  </ul>
</div>

快速基准测试给出了以下结果

  • 100个同步GET请求花了178秒
  • 100个异步GET请求需要10秒

答案 3 :(得分:0)

我知道这是一个古老的话题,但就在昨天我遇到了这个问题。以下信息对某人有用。 我在类似代码(并行http请求)中从LWP获得了几种错误,包括

  • &#34;字符串找到操作员预期在...附近&#34; croak ...&#34;
  • &#34;子程序的深度递归&#34; IO :: Socket :: new&#34; ......内存不足!&#34;
  • 有时请求失败(返回状态500或501)。

在添加以下行后问题似乎消失了:

use IO::File;

不要问我为什么,我不知道:)意外地想出来了。 我正在使用Strawberry Perl 5.24.0。

相关问题