gpt4 book ai didi

perl - 通过具体示例了解 Perl 中的异步

转载 作者:行者123 更新时间:2023-12-03 02:12:17 25 4
gpt4 key购买 nike

我必须编写一个脚本来并行获取一些 URL 并做一些工作。过去我一直用Parallel::ForkManager对于这样的事情,但现在我想学习一些新东西并尝试使用 AnyEvent 进行异步编程(和 AnyEvent::HTTPAnyEvent::Curl::Multi )...但我在理解 AnyEvent 和编写脚本时遇到问题,该脚本应该:

  • 打开一个文件(每一行都是一个单独的 URL)
  • (从现在起并行,但限制为 10 个并发请求)
  • 逐行读取文件(我不想将整个文件加载到内存中 - 它可能很大)
  • 针对该网址发出 HTTP 请求
  • 阅读回复
  • 相应地更新 MySQL 记录
  • (下一个文件行)

我已经阅读了很多手册、教程,但我仍然很难理解阻塞和非阻塞代码之间的差异。我在 http://perlmaven.com/fetching-several-web-pages-in-parallel-using-anyevent 找到了类似的脚本,Szabo 先生解释了基础知识,但我仍然不明白如何实现类似的东西:

...
open my $fh, "<", $file;
while ( my $line = <$fh> )
{
# http request, read response, update MySQL
}
close $fh
...

...并在本例中添加并发限制。

我将非常感谢您的帮助;)

更新

按照池上的建议,我给出了Net::Curl::Multi尝试一下。我对结果非常满意。经过多年的使用Parallel::ForkManager只是为了并发抓取数千个URL,Net::Curl::Multi似乎很棒。这是我的代码 while在文件句柄上循环。它似乎可以正常工作,但考虑到这是我第一次写这样的东西,我想请更有经验的 Perl 用户看一下,并告诉我是否有一些潜在的错误、我错过的东西等。另外,如果我可以问:因为我不完全明白如何Net::Curl::Multi的并发性有效,请告诉我将 MySQL UPDATE 命令(通过 DBI )放入 RESPONSE 中是否会出现任何问题。循环(显然除了更高的服务器负载之外 - 我预计最终脚本将运行大约 50 个并发 N::C::M 工作人员,也许更多)。

#!/usr/bin/perl

use Net::Curl::Easy qw( :constants );
use Net::Curl::Multi qw( );

sub make_request {
my ( $url ) = @_;
my $easy = Net::Curl::Easy->new();
$easy->{url} = $url;
$easy->setopt( CURLOPT_URL, $url );
$easy->setopt( CURLOPT_HEADERDATA, \$easy->{head} );
$easy->setopt( CURLOPT_FILE, \$easy->{body} );
return $easy;
}

my $maxWorkers = 10;

my $multi = Net::Curl::Multi->new();
my $workers = 0;

my $i = 1;
open my $fh, "<", "urls.txt";
LINE: while ( my $url = <$fh> )
{
chomp( $url );
$url .= "?$i";
print "($i) $url\n";
my $easy = make_request( $url );
$multi->add_handle( $easy );
$workers++;

my $running = 0;
do {
my ($r, $w, $e) = $multi->fdset();
my $timeout = $multi->timeout();
select $r, $w, $e, $timeout / 1000
if $timeout > 0;

$running = $multi->perform();
RESPONSE: while ( my ( $msg, $easy, $result ) = $multi->info_read() ) {
$multi->remove_handle( $easy );
$workers--;
printf( "%s getting %s\n", $easy->getinfo( CURLINFO_RESPONSE_CODE ), $easy->{url} );
}

# dont max CPU while waiting
select( undef, undef, undef, 0.01 );
} while ( $workers == $maxWorkers || ( eof && $running ) );
$i++;
}
close $fh;

最佳答案

Net::Curl 是一个非常好的库,速度非常快。此外,它还可以处理并行请求!我建议使用它而不是 AnyEvent。

use Net::Curl::Easy  qw( :constants );
use Net::Curl::Multi qw( );

sub make_request {
my ( $url ) = @_;
my $easy = Net::Curl::Easy->new();
$easy->{url} = $url;
$easy->setopt( CURLOPT_URL, $url );
$easy->setopt( CURLOPT_HEADERDATA, \$easy->{head} );
$easy->setopt( CURLOPT_FILE, \$easy->{body} );
return $easy;
}

my $max_running = 10;
my @urls = ( 'http://www.google.com/' );

my $multi = Net::Curl::Multi->new();
my $running = 0;
while (1) {
while ( @urls && $running < $max_running ) {
my $easy = make_request( shift( @urls ) );
$multi->add_handle( $easy );
++$running;
}

last if !$running;

my ( $r, $w, $e ) = $multi->fdset();
my $timeout = $multi->timeout();
select( $r, $w, $e, $timeout / 1000 )
if $timeout > 0;

$running = $multi->perform();
while ( my ( $msg, $easy, $result ) = $multi->info_read() ) {
$multi->remove_handle( $easy );
printf( "%s getting %s\n", $easy->getinfo( CURLINFO_RESPONSE_CODE ), $easy->{url} );
}
}

关于perl - 通过具体示例了解 Perl 中的异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36898569/

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