簡體   English   中英

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

[英]Perl - Using LWP in multithread program

這是我的代碼:

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。 我有很多錯誤:

線程...異常終止:無法通過... / URI.pm第81行的包“ URI”找到對象方法“ _uric_escape”

在操作符在(eval 10)第8行處“ croak'用法:$ io-> getlines()'”附近找到了字符串

(您需要預先聲明嘶啞聲嗎?)

如果我加

sleep 1;

之前

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

沒關系的

有什么問題?

我不確定為什么,但是在處理動態加載的模塊時似乎存在問題。 在創建線程之前解決該問題,然后顯式加載它們。 換句話說,添加以下內容:

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

認為這里的問題將是內存占用。 畢竟,您正在加載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();
}

否則,基於分叉的方法也可能會更好地工作:

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上,我確實得到了類似的運行時錯誤

它們有些不同,這確實意味着這里必須存在某種競賽條件。

這很奇怪,因為線程應該是獨立的,而不是。

特別是-我的內核炸彈由於內存耗盡而產生了“殺手”,這要歸功於幾GB的內存占用,這是不使用此方法的一個很好的理由。

我的用RHEL和Perl 5.20.2運行代碼的測試用例也偶爾會觸發問題。

我得到的是類似的錯誤-偶爾出現。 我看不到明顯的消息來源想法。 它可能很簡單,就像打開文件描述符太多或消耗的內存太多一樣。 這是相當大的內存負擔。

使用Mojolicious框架,這非常簡單。 Mojo::UserAgent類經設計可在Mojo::IOLoop模塊的幫助下異步工作,盡管同步事務可用,但它們是使用標准異步調用的特殊情況實現的

use strict;
use warnings;

use Mojo;

my $ua = Mojo::UserAgent->new( max_redirects => 5 );

my $n;

for ( 1 .. 100 ) {
  $ua->get('http://dx.doi.org/10.1002/aoc.1067' => \&completed);
  ++$n;
}

Mojo::IOLoop->start;

sub completed {
  my ($ua, $tx) = @_;

  Mojo::IOLoop->stop unless --$n > 0;
}

快速基准測試得出以下結果

  • 100個同步GET請求花費了178秒
  • 100個異步GET請求花了10秒

我知道這是一個老話題,但是就在昨天,我遇到了這個問題。 下面的信息可能對某人有用。 我在類似的代碼(並行http請求)中從LWP中得到了幾種錯誤,包括

  • “字符串在“吱吱聲”附近的……處發現了操作員期望的位置
  • “對子例程“ IO :: Socket :: new”的深度遞歸...內存不足!”
  • 有時,請求只是失敗了(返回狀態500或501)。

我添加以下行后,問題似乎消失了:

use IO::File;

不要問我為什么,我不知道:)偶然發現了這個問題。 我正在使用Strawberry Perl 5.24.0。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM