Muszę napisać skrypt, który pobiera kilka adresów URL równolegle i wykonuje pewną pracę. W przeszłości zawsze używałem Parallel::ForkManager
takich rzeczy, ale teraz chciałem nauczyć się czegoś nowego i spróbować programowania asynchronicznego z AnyEvent
(i AnyEvent::HTTP
lub AnyEvent::Curl::Multi
) ... ale mam problem ze zrozumieniem AnyEvent i napisaniem skryptu, który powinien:Zrozumienie asynchronizacji w perlu na konkretnym przykładzie
- otworzyć plik (każdy wiersz jest oddzielna URL)
- (od teraz równolegle, ale z ograniczeniem do karm 10 jednoczesnych żądań)
- odczytu pliku linia po linii (nie chcę załadować cały plik do pamięci - może być duży)
- utworzyć żądanie HTTP f albo że URL
- odpowiedź odczytu
- aktualizacje rekord MySQL odpowiednio
- (następna linia plik)
Czytałem wiele podręczniki, samouczki, ale to nadal trudno mi zrozumieć różnice między blokowania i non blokujący kod. Znalazłem podobny scenariusz w http://perlmaven.com/fetching-several-web-pages-in-parallel-using-anyevent, gdzie pan Szabo wyjaśnia podstawy, ale ja wciąż nie mogę zrozumieć, jak zaimplementować coś takiego:
...
open my $fh, "<", $file;
while (my $line = <$fh>)
{
# http request, read response, update MySQL
}
close $fh
...
... i dodać limitu współbieżności w tym przypadku.
Byłbym bardzo wdzięczny za pomoc;)
UPDATE
Za radą Ikegami za dałem Net::Curl::Multi
spróbować. Jestem bardzo zadowolony z wyników. Po latach używania Parallel::ForkManager
tylko dla równoczesnego zbierania tysięcy adresów URL, Net::Curl::Multi
wydaje się być niesamowity. Oto mój kod z pętlą while
na uchwycie pliku. Wydaje się działać tak, jak powinno, ale biorąc pod uwagę, że po raz pierwszy piszę coś takiego, chciałbym poprosić bardziej doświadczonych użytkowników Perla o sprawdzenie i powiedzenie, czy są jakieś potencjalne błędy, coś, za czym tęskniłem itp. . jeśli mogę zapytać: ponieważ nie rozumiem w pełni, jak działa współbieżność Net::Curl::Multi
, proszę powiedz mi, czy powinienem spodziewać się problemów z wprowadzeniem polecenia UPDATE do MySQL (przez DBI
) wewnątrz pętli RESPONSE
(poza oczywiście większym obciążeniem serwera - spodziewam się ostatecznego skrypt uruchamiany z około 50 współbieżnymi pracownikami N::C::M
, może więcej).
#!/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;
Dostaję dużo „funkcja zwrotna nie jest ustawiony ". Wygląda na to, że pokazuje, kiedy istnieje domena w Hostu URL. Nie otrzymuję tego błędu, jeśli używam adresu IP. Ponadto, jeśli wstawię f.e. 'print" ma to! ";' gdzie '' process $ easy' jest, zawartość strony jest automatycznie drukowana. – alan
Naprawiono to, aby zawartość była przechowywana w $ łatwym do wydrukowania. Nie dostaję błędu zwrotnego, który otrzymujesz?[Wypróbuj ze zmianą. To może być powiązane] – ikegami
Dzięki za pomoc. Niestety nadal otrzymuję "funkcja oddzwaniania nie jest ustawiona". Właściwie 4 razy, to Twój "printf". Nie wiem, skąd pochodzi. – alan