2013-04-05 10 views
10

Supponiamo di avere un numero di attività in un'applicazione che può finire in qualsiasi ordine. E ho bisogno di eseguire del codice quando tutti i compiti sono finiti. Se ciò è importante, l'applicazione è in esecuzione su AnyEvent, ma senza Coro.Richiamate multiplexing

In un certo senso, AnyEvent '$cv->begin/$cv->end consentire quello che voglio. Tuttavia, mi piacerebbe avere un controllo più fine. Ad esempio, mi piacerebbe non essere in grado di "finire" un compito due volte. Anche la capacità di raccogliere dati da tutte le attività sarebbe piacevole.

Naturalmente, questo può essere fatto. Imposta molti callback che condividono un hash; cancella le chiavi da quell'hash quando termina un'attività; chiama il megacallback quando l'hash è vuoto. Mi chiedo se c'è un modo più civile di farlo, forse un modulo CPAN?

Ad esempio, ecco un'API immaginaria che soddisferà il mio bisogno.

#!/usr/bin/perl -w 
use strict; 

use Some::Module; 

# Set goals 
my $cb = Some::Module->new(sub { say 'BOOM!' }); 
$cb->begin(qw(foo bar)); 

# Much later, as tasks start getting done 
$cb->end(foo => 42);  # "return" value from task 'foo' 
$cb->begin('baz');   # can add more tasks, why not 
$cb->end('bar');   # just finish task 'bar' 
# still waiting for 'baz' to finish at this point 

# Finally, last hanging task is done 
$cb->end(baz => 137);  # BOOM! 
# at this point, sub {}->({ foo=>42, bar=>undef, baz=>137 }) 
#  has been called 

Vedere anche il mio perlmonks question.

C'è qualcosa del genere?

risposta

3

Si potrebbe prendere in considerazione Future.

In particolare, per l'attesa su molte cose da completare, è possibile utilizzare Future->needs_all o simili:

my @things = ... # generate Futures to represent each thing 

Future->needs_all(@things) 
    ->on_done(sub { 
    # some code here when all the things are done 
    }); 

In alternativa, si potrebbe anche provare Async::MergePoint che dà un API molto più vicino a quello che si aveva in mente:

+0

Il MergePoint è * esattamente * quello che ho chiesto, grazie. – Dallaylaen

+0

Anche il futuro sembra promettente. Grazie ancora. Vorrei poter invocare due volte. – Dallaylaen

2

Non sono certo esperto in roba asincrona, ma penso che Mojo::IOLoop::Delay (parte della suite Mojolicious) abbia un'interfaccia simile. Si noti che Mojo :: IOLoop può essere utilizzato con EV and thus AnyEvent.

Ecco un esempio da the cookbook:

use Mojo::UserAgent; 
use Mojo::IOLoop; 

# Synchronize non-blocking requests portably 
my $ua = Mojo::UserAgent->new; 
my $delay = Mojo::IOLoop->delay(sub { 
    my ($delay, $tx, $tx2) = @_; 
    ... 
}); 
$ua->get('http://mojolicio.us'   => $delay->begin); 
$ua->get('http://mojolicio.us/perldoc' => $delay->begin); 
$delay->wait unless Mojo::IOLoop->is_running; 

Notare inoltre che $delay->begin restituisce un callback che è essenzialmente il metodo end.

Altri esempi, come un interessante concetto di "passaggi" sono riportati nella documentazione :: Delay.

EDIT

Ecco un breve esempio. Si noti che una piccola modifica della sintassi ha avuto luogo nella classe di ritardo JUST, quindi funziona solo con Mojolicious 3.93+, non che ciò non fosse possibile prima, ma la sintassi era leggermente diversa.

#!/usr/bin/env perl 

use strict; 
use warnings; 
use v5.10; 

use Mojo::IOLoop; 

my $delay = Mojo::IOLoop->delay(sub{shift; say for @_}); 

my $end_foo = $delay->begin(0); 
Mojo::IOLoop->timer(0 => sub { $end_foo->('hi') }); 

my $end_bar = $delay->begin(0); 
Mojo::IOLoop->timer(0 => sub { $end_bar->('bye') }); 

$delay->wait unless $delay->ioloop->is_running; #start loop if necessary 

Qui si crea l'oggetto di ritardo, l'argomento è un callback finish evento. Per ogni azione asincrona, chiamo begin che restituisce una richiamata end. Per impostazione predefinita, questi callback eliminano il loro primo argomento per rimuovere un invocante superfluo (vedi esempio sopra), ma non ne abbiamo, quindi passiamo a 0 per indicare che non lo facciamo. Per ogni azione, rimando semplicemente con un timer di attesa zero. Gli argomenti alla fine del callback vengono quindi messi in coda per l'evento finale, in ordine. Tada!

Problemi correlati