Mee*_*tya 3 parallel-processing perl asynchronous
我开始学习AnyEvent并且有一些麻烦.我完全误解了如何获得异步利润,fe:
#!/usr/bin/env perl
package LatencySub;
use strict;
use warnings;
use AnyEvent;
# sub for emulate latency - is it right way?
sub do_delay{
my ($name, $delay) = (@_);
my $cv = AE::cv;
my $timer = AE::timer $delay, 0, sub { $cv->send() };
$cv->recv;
return $name.' proceed, delay is '.$delay;
};
package main;
use 5.12.0;
use warnings;
use Smart::Comments;
use AnyEvent;
my @list = (
{ name => 'first', delay => 1 },
{ name => 'second', delay => 1 },
{ name => 'third', delay => 2 }
);
sub process_cb {
my ( $name, $delay, $cb ) = @_;
my $result = LatencySub::do_delay( $name, $delay );
$cb->($result);
}
my %result;
my $cv = AE::cv;
# outer loop
$cv->begin (sub { shift->send (\%result) });
my $before_time = AE::time;
### foreach start...
foreach my $entity (@list) {
$cv->begin;
process_cb (
$entity->{'name'},
$entity->{'delay'},
sub {
$result{$entity->{'name'}} = shift;
$cv->end;
}
);
}
### foreach end...
$cv->end;
my $time_all = AE::time - $before_time;
### $time_all
### %result
Run Code Online (Sandbox Code Playgroud)
在输出我得到:
### foreach start...
### foreach end...
### $time_all: '4.02105116844177'
### %result: {
### first => 'first proceed, delay is 1',
### second => 'second proceed, delay is 1',
### third => 'third proceed, delay is 2'
### }
Run Code Online (Sandbox Code Playgroud)
所有延迟总和(1 + 1 + 2)eq $ time_all - 4秒.所以,根本没有利润.
为什么它以及如何(并且可能?)创建"正确"的回调?
调用$cv->recv
将被阻塞直到->send
被调用,因此do_delay()
需要$delay
秒才能返回.
这是一个产生三个线程并等待所有线程完成的示例:
use strict;
use warnings;
use AnyEvent;
sub make_delay {
my ($name, $delay, $cv) = (@_);
$cv->begin;
return AE::timer $delay, 0, sub { warn "done with $name\n"; $cv->end };
}
my $cv = AE::cv;
my @timers = (make_delay("t1", 3, $cv),
make_delay("t2", 5, $cv),
make_delay("t3", 4, $cv)
);
$cv->recv;
Run Code Online (Sandbox Code Playgroud)
不要使用 condvars,除非在等待事件完成时阻止顶级程序。使用 condvars 使得重用代码变得非常困难;任何内部具有 condvar 的函数永远不能在具有另一个包含 condvar 的函数的程序中安全地使用。(如果您从不调用recv
而仅使用,则这是不正确的cb
。但是......这仍然是危险的,并且对于那些不知道自己在做什么的人来说不适合。)
我的规则:如果文件名以 结尾.pm
,则没有条件变量!
如果您想并行运行多个任务,并在所有结果可用后运行更多代码,请尝试Event::Join:
sub delay($$) {
AnyEvent->timer( after => $_[0], cb => $_[1] );
}
my $join = Event::Join->new(
on_completion => sub { say "Everything is done" }
events => [qw/t1 t2 t3/],
);
delay 1, $join->event_sender_for('t1');
delay 2, $join->event_sender_for('t2');
delay 3, $join->event_sender_for('t3');
Run Code Online (Sandbox Code Playgroud)
然后,3秒后,你会看到“一切都完成了”。Event::Join 就像条件变量上的开始和结束,但永远不会阻止您的程序。因此很容易重用使用它的代码。此外,事件是命名的,因此您可以将结果收集为哈希,而不是在调用其他回调时仅调用回调。