2013-04-05 32 views
10

Giả sử tôi có một số tác vụ trong một ứng dụng có thể hoàn thành theo bất kỳ thứ tự nào. Và tôi cần chạy một số mã khi tất cả các tác vụ đã hoàn thành. Nếu điều đó quan trọng, ứng dụng đang chạy dưới AnyEvent, nhưng không có Coro.Gọi lại ghép kênh

Ở một mức độ nào đó, AnyEvent 's $cv->begin/$cv->end cho phép những gì tôi muốn. Tuy nhiên, tôi muốn có sự kiểm soát chi tiết hơn. Ví dụ, tôi muốn không thể "hoàn thành" một nhiệm vụ hai lần. Khả năng thu thập dữ liệu từ tất cả các nhiệm vụ cũng sẽ tốt đẹp.

Tất nhiên, điều này có thể được thực hiện. Thiết lập nhiều callback chia sẻ một hash; xóa các khóa khỏi băm đó bất cứ khi nào một tác vụ kết thúc; gọi megacallback khi băm rỗng. Tôi tự hỏi nếu có một cách văn minh hơn để làm điều đó, có thể một số mô-đun CPAN?

Ví dụ: đây là API tưởng tượng sẽ đáp ứng nhu cầu của tôi.

#!/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 

Xem thêm perlmonks question.

Có điều gì giống như thế này?

Trả lời

3

Bạn có thể muốn xem xét Future.

Cụ thể, đã chờ đợi vào nhiều yếu tố để hoàn thành, bạn có thể sử dụng Future->needs_all hoặc tương tự:

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

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

Ngoài ra, bạn cũng có thể thử Async::MergePoint mang đến cho một API gần gũi hơn với những gì bạn có trong tâm trí:

my $mp = Async::MergePoint->new(needs => [qw(foo bar)]); 
$mp->close(on_done => sub { 
    # some code here when all the things are done 
}); 

$mp->done(foo => $value); 
$mp->done(bar =>); 
+0

MergePoint là * chính xác * những gì tôi đã yêu cầu, cảm ơn. – Dallaylaen

+0

Tương lai có vẻ đầy hứa hẹn. Cảm ơn một lần nữa. Tôi ước tôi có thể upvote hai lần. – Dallaylaen

2

Tôi chắc chắn không có chuyên gia về công cụ không đồng bộ, nhưng tôi nghĩ rằng Mojo::IOLoop::Delay (một phần của bộ Mojolicious) có giao diện tương tự. Lưu ý rằng Mojo :: IOLoop có thể được sử dụng với EV and thus AnyEvent.

Dưới đây là một ví dụ từ 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; 

Ngoài ra, lưu ý rằng $delay->begin trả về một callback mà chủ yếu là phương pháp end.

Ví dụ khác, như khái niệm 'bước' thú vị được hiển thị trong :: Tài liệu trì hoãn.

EDIT

Dưới đây là một ví dụ nhanh. Lưu ý rằng một thay đổi cú pháp nhỏ đã JUST xảy ra trong lớp trễ vì vậy điều này chỉ hoạt động với Mojolicious 3.93+, không phải điều này là không thể trước đây, nhưng cú pháp hơi khác một chút.

#!/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 

Ở đây chúng ta tạo ra các đối tượng chậm trễ, lập luận là một callback finish sự kiện. Đối với mỗi hành động không đồng bộ, tôi gọi begin trả về một cuộc gọi lại end. Theo mặc định, các callbacks này bỏ qua đối số đầu tiên của chúng để loại bỏ một invocant thừa (xem ví dụ ở trên), nhưng chúng ta không có chúng, vì vậy chúng ta vượt qua 0 để cho biết không làm điều đó. Đối với mỗi hành động, tôi chỉ đơn giản trì hoãn với bộ đếm thời gian chờ 0. Các đối số để gọi lại kết thúc sau đó được xếp hàng đợi cho sự kiện kết thúc, theo thứ tự. Tada!

Các vấn đề liên quan